Huh! I did not realize that CSS custom properties had their own resolution behavior for how !important
works in their values. Uh, despite writing a guide about them. 😬 But hey it’s now updated.
Stefan Judis documents it clearly. The deal is that !important
is not at all used in the final value. So:
div {
--color: red !important;
color: var(--color);
color: yellow;
}
It kinda feels like red
should win, but because !important
is ultimately stripped from the custom property value, yellow
wins it out. And it’s not because the color
declaration comes last — if color: red !important;
was the first declaration, then red
would win.
But it’s not like !important
is just stripped and ignored; it’s used in a scoped way, affecting which custom property value wins. But then !important
is gone when that value is applied. Stefan’s example:
div {
/*
`!important` overrules the
other `--color` definitions
*/
--color: red !important;
color: var(--color);
}
.class {
--color: blue;
}
#id {
--color: yellow;
}
This feels weird (to me) as you’d think yellow
declared on #id
would win because it has the highest specificity. But that’s the deal with the scoped behavior — !important
makes red
the winner, then is applied to the color
as such.
Two things to remember:
Custom properties are properties, so
!important
works on them the same way.!important
is not part of property value (it has never been).I’m not sure why this would be surprising,
!important
is not part of the value but part of the rule, in this case it affects how--color
is resolved and that’s it.It just IS surprising to me, sorry yo.
It’s like if in JavaScript if you set
foo = "bing bong"
and thenconsole.log(foo)
saidbing
because you just had to know thatbong
is a super special thing that gets stripped from values.I think the more interesting is how keywords like ‘inherit’ and ‘initial’ affect custom properties. There is no way to pass those keywords as the value, so in the following example the background of .child would be blue, not yellow:
‘initial’ is even more interesting, it “deletes” the variable (because it was initially non-existent), therefore when used later with a fallback – the fallback value will be used:
Just spitballin’ here, but if you’re creating a consumable, themeable component, could you use
!important
to create “private”, immutable Custom Properties? This way, you wouldn’t have to use something like Sass for “internal” variables (for internally-shared and repeatable bits of code, but not something you want consumers to use) and Custom Props as your external styling API (for lack of a better term).Something I found extra surprising:
…outputs blue text when I’d expect red