What Can You Put in a CSS Variable? / Coder’s Block
A reminder that the contens of custom properties don’t have to be valid property values:
From a syntax perspective, CSS variables are “extremely permissive”.
A reminder that the contens of custom properties don’t have to be valid property values:
From a syntax perspective, CSS variables are “extremely permissive”.
Ever wanted to set some text in 70% Times New Roman and 30% Arial? Me neither. But now, thanks to variable fonts, you can!
This is such a clever use of variable fonts!
We can use a lighter font weight to make the text easier to read whenever dark mode is active.
A history of typesetting from movable type to variable fonts.
Everything you ever wanted to know about variable fonts, gathered together into one excellent website.
In this interview, Biance Berning says:
Cassie Evans from Clearleft is an interesting person to follow as she combines web animation with variable font technology, essentially exploring the technology’s practicality and expression.
Hells yeah!
We’re only just scratching the surface of what variable fonts can do within more interactive and immersive spaces. I think we’ll see a lot more progress and experimentation with that as time goes on.
Play around with this variable font available soon from Google Fonts in monospaced and sans-serif versions.
A showcase of fun experiments with variable fonts, courtesy of Mandy.
Don’t write
fopen
when you can writeopenFile
. WritethrowValidationError
and notthrowVE
. Call that namefunction
and notfct
. That’s German naming convention. Do this and your readers will appreciate it.
Heydon cracks me up—his Patterns Day is going to have you crying with laughter; guaranteed!
Here he is talking about custom properties in CSS as part of his Making Future Interfaces video series.
Here’s a tiny lesson that I picked up from Trys that I’d like to share with you…
I was working on some upcoming changes to the Clearleft site recently. One particular component needed some SVG background images. I decided I’d inline the SVGs in the CSS to avoid extra network requests. It’s pretty straightforward:
.myComponent {
background-image: url('data:image/svg+xml;utf8,<svg> ... </svg>');
}
You can basically paste your SVG in there, although you need to a little bit of URL encoding: I found that converting #
to %23
to was enough for my needs.
But here’s the thing. My component had some variations. One of the variations had multiple background images. There was a second background image in addition to the first. There’s no way in CSS to add an additional background image without writing a whole background-image
declaration:
.myComponent--variant {
background-image: url('data:image/svg+xml;utf8,<svg> ... </svg>'), url('data:image/svg+xml;utf8,<svg> ... </svg>');
}
So now I’ve got the same SVG source inlined in two places. That negates any performance benefits I was getting from inlining in the first place.
That’s where Trys comes in. He shared a nifty technique he uses in this exact situation: put the SVG source into a custom property!
:root {
--firstSVG: url('data:image/svg+xml;utf8,<svg> ... </svg>');
--secondSVG: url('data:image/svg+xml;utf8,<svg> ... </svg>');
}
Then you can reference those in your background-image
declarations:
.myComponent {
background-image: var(--firstSVG);
}
.myComponent--variant {
background-image: var(--firstSVG), var(--secondSVG);
}
Brilliant! Not only does this remove any duplication of the SVG source, it also makes your CSS nice and readable: no more big blobs of SVG source code in the middle of your style sheet.
You might be wondering what will happen in older browsers that don’t support CSS custom properties (that would be Internet Explorer 11). Those browsers won’t get any background image. Which is fine. It’s a background image. Therefore it’s decoration. If it were an important image, it wouldn’t be in the background.
Progressive enhancement, innit?
Cassie posted a neat tiny lesson that she’s written a reduced test case for.
Here’s the situation…
CSS custom properties are fantastic. You can drop them in just about anywhere that a property takes a value.
Here’s an example of defining a custom property for a length:
:root {
--my-value: 1em;
}
Then I can use that anywhere I’d normally give something a length:
.my-element {
margin-bottom: var(--my-value);
}
I went a bit overboard with custom properties on the new Patterns Day site. I used them for colour values, font stacks, and spacing. Design tokens, I guess. They really come into their own when you combine them with media queries: you can update the values of the custom properties based on screen size …without having to redefine where those properties are applied. Also, they can be updated via JavaScript so they make for a great common language between CSS and JavaScript: you can define where they’re used in your CSS and then update their values in JavaScript, perhaps in response to user interaction.
But there are a few places where you can’t use custom properties. You can’t, for example, use them as part of a media query. This won’t work:
@media all and (min-width: var(--my-value)) {
...
}
You also can’t use them in generated content if the value is a number. This won’t work:
:root {
--number-value: 15;
}
.my-element::before {
content: var(--number-value);
}
Fair enough. Generated content in CSS is kind of a strange beast. Eric delivered an entire hour-long talk at An Event Apart in Seattle on generated content.
But Cassie found a workaround if the value you want to put into that content
property is numeric. The CSS counter
value is a kind of generated content—the numbers that appear in front of ordered list items. And you can control the value of those numbers from CSS.
CSS counters work kind of like variables. You name them and assign values to them using the counter-reset
property:
.my-element {
counter-reset: mycounter 15;
}
You can then reference the value of mycounter
in a content
property using the counter
value:
.my-element {
content: counter(mycounter);
}
Cassie realised that even though you can’t pass in a custom property directly to generated content, you can pass in a custom property to the counter-reset
property. So you can do this:
:root {
--number-value: 15;
}
.my-element {
counter-reset: mycounter var(--number-value);
content: counter(mycounter);
}
In a roundabout way, this allows you to use a custom property for generated content!
I realise that the use cases are pretty narrow, but I can’t help but be impressed with the thinking behind this. Personally, I would’ve just read that generated content doesn’t accept custom properties and moved on. I would’ve given up quickly. But Cassie took a step back and found a creative pass-the-parcel solution to the problem.
I feel like this is a hack in the best sense of the word: a creatively improvised solution to a problem or limitation.
I was trying to display the numeric value stored in a CSS variable inside generated content… Turns out you can’t do that. But you can do this… codepen.io/cassie-codes/p… (not saying you should, but you could)
I think Cathy might’ve buried the lede:
The knock on effect of this was removing media queries. As I moved towards some of the more modern features of CSS the need to target specific screen sizes with unique code was removed.
But on the topic of Sass, layout is now taken care of with CSS grid, variables are taken care of with CSS custom properties, and mixins for typography are taken care of with calc()
.
Personally, I’ve always found the most useful feature of Sass to simply be that you can have lots of separate Sass files that get combined into one CSS file—very handy for component libraries.
I had to read through this twice, but I think I get it now (I’m not the sharpest knife in the drawer). Very useful if you’re doing theming in CSS.
Variable fonts are a very exciting and powerful new addition to the toolbox of web design. They was very much at the centre of discussion at this year’s Ampersand conference.
A lot of the demonstrations of the power of variable fonts are showing how it can be used to make letter-by-letter adjustments. The Ampersand website itself does this with the logo. See also: the brilliant demos by Mandy. It’s getting to the point where logotypes can be sculpted and adjusted just-so using CSS and raw text—no images required.
I find this to be thrilling, but there’s a fly in the ointment. In order to style something in CSS, you need a selector to target it. If you’re going to style individual letters, you need to wrap each one in an HTML element so that you can then select it in CSS.
For the Ampersand logo, we had to wrap each letter in a span
(and then, becuase that might cause each letter to be read out individually instead of all of them as a single word, we applied some ARIA shenanigans to the containing element). There’s even a JavaScript library—Splitting.js—that will do this for you.
But if the whole point of using HTML is that the content is accessible, copyable, and pastable, isn’t a bit of a shame that we then compromise the markup—and the accessibility—by wrapping individual letters in presentational tags?
What if there were an ::nth-letter
selector in CSS?
There’s some prior art here. We’ve already got ::first-letter
(and now the initial-letter
property or whatever it ends up being called). If we can target the first letter in a piece of text, why not the second, or third, or nth?
It raises some questions. What constitutes a letter? Would it be better if we talked about ::first-character
, ::initial-character
, ::nth-character
, and so on?
Even then, there are some tricksy things to figure out. What’s the third character in this piece of markup?
<p>AB<span>CD</span>EF</p>
Is it “C”, becuase that’s the third character regardless of nesting? Or is it “E”, becuase techically that’s the third character token that’s a direct child of the parent element?
I imagine that implementing ::nth-letter
(or ::nth-character
) would be quite complex so there would probably be very little appetite for it from browser makers. But it doesn’t seem as problematic as some selectors we’ve already got.
Take ::first-line
, for example. That violates one of the biggest issues in adding new CSS selectors: it’s a selector that depends on layout.
Think about it. The browser has to first calculate how many characters are in the first line of an element (like, say, a paragraph). Having figured that out, the browser can then apply the styles declared in the ::first-line
selector. But those styles may involve font sizing updates that changes the number of characters in the first line. Paradox!
(Technically, only a subset of CSS of properties can be applied to ::first-line
, but that subset includes font-size
so the paradox remains.)
I checked to see if ::first-line
was included in one of my favourite documents: Incomplete List of Mistakes in the Design of CSS. It isn’t.
So compared to the logic-bending paradoxes of ::first-line
, an ::nth-letter
selector would be relatively straightforward. But that in itself isn’t a good enough reason for it to exist. As the CSS Working Group FAQs say:
The fact that we’ve made one mistake isn’t an argument for repeating the mistake.
A new selector needs to solve specific use cases. I would argue that all the letter-by-letter uses of variable fonts that we’re seeing demonstrate the use cases, and the number of these examples is only going to increase. The very fact that JavaScript libraries exist to solve this problem shows that there’s a need here (and we’ve seen the pattern of common JavaScript use-cases ending up in CSS before—rollovers, animation, etc.).
Now, I know that browser makers would like us to figure out how proposed CSS features should work by polyfilling a solution with Houdini. But would that work for a selector? I don’t know much about Houdini so I asked Una. She pointed me to a proposal by Greg and Tab for a full-on parser in Houdini. But that’s a loooong way off. Until then, we must petition our case to the browser gods.
This is not a new suggestion.
Anne Van Kesteren proposed ::nth-letter
way back in 2003:
While I’m talking about CSS, I would also like to have
::nth-line(n)
,::nth-letter(n)
and::nth-word(n)
, any thoughts?
Trent called for ::nth-letter
in January 2011:
I think this would be the ideal solution from a web designer’s perspective. No javascript would be required, and 100% of the styling would be handled right where it should be—in the CSS.
Chris repeated the call in October of 2011:
Of all of these “new” selectors,
::nth-letter
is likely the most useful.
In 2012, Bram linked to a blog post (now unavailable) from Adobe indicating that they were working on ::nth-letter
for Webkit. That was the last anyone’s seen of this elusive pseudo-element.
In 2013, Chris (again) included ::nth-letter
in his wishlist for CSS. So say we all.
Nick demonstrates the responsive power of variable fonts by recreating a lovely design from Jacob Jongert.
Grab that browser window and get squishin’!
In defence of the cascade (especially now that we’ve got CSS custom properties).
I think embracing CSS’s cascade can be a great way to encourage consistency and simplicity in UIs. Rather than every new component being a free for all, it trains both designers and developers to think in terms of aligning with and re-using what they already have.
Remember, every time you set a property in CSS you are in fact overriding something (even if it’s just the default user agent styles). In other words, CSS code is mostly expressing exceptions to a default design.
This is a great interview with Rich on all things related to web typography—including, of course, variable fonts.
I’m so lucky that I literally get to work side by side with Rich; I get to geek out with him about font stuff all the time.
A fun way to play around with the options in variable fonts.
Rob attended the excellent Ampersand event last Friday and he’s made notes for each and every talk.