My question is why CSS Variables needed to add the concept of fallback and doesn't just rely on inheritance like the other CSS properties.
For example:
:root {
--color1: red;
}
body {
color: var(--color1);
}
body p {
color: var(--color2);
--color2: blue;
}
body span {
--color3: green;
color: var(--color3);
color: yellow;
color: var(--color4);
}
<body>
Text 1
<p>
Text 2
</p>
<span>
Text 3
</span>
</body>
Text 3 ends up in being red instead of green or yellow. Although there are valid properties on the level, it takes the parent color value, instead of verifying if there are other valid values on the same level. This happens when the variable name is invalid.
Apparently there is a special fallback for CSS variables so you need to use something like:
color: var(--color4, yellow);
But this means again duplication of the color, since
color: var(--color4, --color3);
does not work. Neither is:
color: var(--color3, yellow, blue);
or any other multiple values.
Also no support for keywords like inherit, currentColor, initial, etc. So I'm not sure how I could rely on the inheritance since apparently I need to be very explicit with the given values. Tested on Firefox 57.0.1 and Chrome 63.
I know the CSS variables are still as Working Draft so maybe that's why the current behavior.
The fallback value of a CSS variable is the second and optional argument of the var () function. For example, let’s consider we have some .box elements whose background is set to a variable of --c: If we haven’t explicitly specified a value for the --c variable elsewhere, then the fallback value #ccc is used.
This answer makes no attempt to address why var () was designed to use fallbacks instead of falling back on inheritance by default (though the fact that not all properties are inherited is a plausible, if not downright obvious, explanation).
First off, the fallback can be another CSS variable, which can have a CSS variable fallback itself and… we can fall down a really deep rabbit hole this way! Secondly, a comma separated list is a perfectly valid fallback value.
Furthermore, you are using it wrong, the correct way to use the fallback from var () should be this: var () only accepts 2 arguments, the value you want to use and the fallback.
As JoseAPL has stated, the reason var()
expressions accept a fallback argument instead of defaulting to inheritance is simply because while custom properties do inherit, not all of the standard properties you will use them with do.
On the other hand, if you're asking why a var()
expression doesn't default to the next best-cascaded value, that's because by the time the var()
expression is evaluated, there are no other values to fall back to, because every other declaration in the cascade has been erased. See section 3.1, which defines the term invalid at computed-value time:
Note: The invalid at computed-value time concept exists because variables can’t "fail early" like other syntax errors can, so by the time the user agent realizes a property value is invalid, it’s already thrown away the other cascaded values.
Having said that, you can provide a custom property as a fallback value (as long as it's not the same one, for the same reason explained above) — that custom property just needs to appear in its own var()
expression, since the fallback value is, well, a declaration value, not a property name.
So the result is a var()
nested inside another var()
:
body span {
--color3: green;
color: var(--color3);
color: yellow;
color: var(--color4, var(--color3));
}
:root {
--color1: red;
}
body {
color: var(--color1);
}
body p {
color: var(--color2);
--color2: blue;
}
body span {
--color3: green;
color: var(--color3);
color: yellow;
color: var(--color4, var(--color3));
}
<body>
Text 1
<p>
Text 2
</p>
<span>
Text 3
</span>
</body>
Not all properties in CSS are inherited, see these links so you can see which CSS properties are inherited and how inheritance is applied:
https://www.w3.org/TR/CSS22/propidx.html
https://developer.mozilla.org/en-US/docs/Web/CSS/inheritance
The order you declare duplicated properties is important.
If the color you want to be applied is green
this is not the same:
// correct way to declare fallback color, it will be green and yellow if --color3 was not defined
body span {
--color3: green;
color: yellow;
color: var(--color3);
}
as:
body span { // incorrect way to declare fallback color
--color3: green;
color: var(--color3);
color: yellow;
color: var(--color4);
}
The property
color: var(--color4);
will be taken since there is no invalid syntax on this declaration but since there is no variable declared as--color4
the inherited color will be applied (in this case frombody { color: var(--color1) }
)Because
color
is a inherited property
Using the fallback with var()
is another solution, but the previous one is a fallback for older browsers that don't support var()
Furthermore, you are using it wrong, the correct way to use the fallback from var()
should be this:
color: var(--color4, var(--color3));
or this:
color: var(--color4, var(--color3, yellow));
var()
only accepts 2 arguments, the value you want to use and the fallback.
See the syntax of how to use it in the following link
Since var()
is not available in all browsers yet, using duplicated properties the right way is the option I would go with, or you can go with both of them.
:root {
--color1: red;
}
body {
color: var(--color1);
}
body p {
color: var(--color2);
--color2: blue;
}
body span {
--color3: green;
color: yellow;
color: var(--color4, var(--color3));
}
<body>
Text 1
<p>
Text 2
</p>
<span>
Text 3
</span>
</body>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With