At the latest ParisWeb conference, Gaël Poupard gave a very interesting talk about CSS Custom properties. His talk was in french, but you’ll find here a recap in english of most of the clever uses of CSS properties he shared with us.
CSS custom properties are CSS properties that live in user-land; they are not part of any official specification and you can create as many as you want, with any silly name you’d like and put anything as their value. The only constraint is that they must start with a double dash (like
They are often called CSS Variables, but this is not their official name. Technically they are only variables when they are read through the
var(--myLittlePony) will evaluate to
pink, so you can do
var() also accepts an optional second argument as a fallback value so
var(--myLittlePony, ‘black’) will evaluate to
black if you didn’t define
Conceptually, they are pretty similar to variables you might have in your SCSS/LESS preprocessor, but even more powerful they are part of the official spec and you can access and modify them live in the browser.
If you define
--myLittlePony on your
<body>, all your elements will be able to reference it. Your buttons can use
background-color: var(--myLittlePony), your links can have
Arithmetic operations can also be applied using calc().
font-size: calc(12px * var(--fontScale)) for example will allow you to scale your font based on the
--fontScale custom property. Set it to
1 for the default one, and to
1.2 to implement some kind of zooming/dezooming function. You could also chose to implement a different default
--fontScale when based on the viewport size.
The same logic could be applied to margins, paddings or even colors through the use of the
hsl() function and some custom
--light properties. Applications are virtually limitless here.
A specific application of the above principle is to use pseudo-boolean values (
1) to switch some features on or off. For example, if we have
animation: bounce calc(var(--enableAnimation) * 1s) infinite and
--enableAnimation set to
1, it will play normally. But if we set
--enableAnimation: 0 then the whole duration is evaluated to
0, disabling it.
This simple feature switch principle can be applied to disable shadows on low-end devices or animation in our screenshot testing pipeline.
The fallback value of the
var() method can actually accept another call to
var(), creating a deep nested system of fallback values.
Styles for input elements and form buttons are notoriously difficult to write and maintain as they have to deal with a plethora of conflicting states: hover, disabled, focus, valid, invalid, pending, clicked, primary, secondary, etc. Some of them are mutually exclusive while others can be stacked on top of each other.
Instead of writing more and more specific selectors to handle all the cases and overwriting rules, the nested fallback mechanism of the
var() method can be used instead and might offer an easier alternative.
One last interesting thing to note is that Shadow DOM nodes inherits CSS custom properties from their parents. This means that you can pass CSS custom properties to a Shadow DOM node, and it can then use them to style its content. This would act as some sort of API between the Shadow DOM node and the outside world.