I set up some CSS rules like:
.example {
color: white;
background-color: darkgray;
background-color: var(--bg-color);
background-color: rgb(from var(--bg-color) r g b / 0.5);
}
in the expectation that if a browser didn’t understand the fairly new relative color syntax (or the fairly old but not ancient var()
syntax) that my element would still be legible. But in older browsers I still end up with a transparent (getComputedStyle($0).backgroundColor === rgb(0,0,0,0)
) background rather than the darker one I need for legibility.
Why are both of these true?
- the browser doesn’t understand the syntax (as evidenced by it not using the relative color)
- the browser uses the rule anyway (as evidenced by the fallback rules going unused)
The CSS Values spec says re. "Partial implementations" that:
So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid (and ignore as appropriate) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents must not selectively ignore unsupported component values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.
So my understanding is that a browser which doesn’t understand or support my relative color syntax should be ignoring that entire declaration. So why isn’t it using one of the earlier fallbacks?
3
Answers
As another user pointed out in a (now-deleted?) comment on my question, this only happens when
var()
is used in the troublesome selector. If I try to use a relative color likergb(from red r g b / 0.5)
then my desired fallbacks are used.I believe the answer lies in the spec re. invalid CSS variables which says:
which results not in discarding the rule but rather it will behave:
There's even a note that further reinforces this (after giving a very similar example to mine using
background-color
even 😁):I don't know why the user agent has to have necessarily thrown away the other values (that seems like an implementation or at least design choice?), but regardless it does explain it!
In short:
The presence of the
var()
means the browser uses the rule hoping it will resolve to something valid. But then if it turns out not to be valid in the end, it's too late to discard it and it resets the property instead.you could try the following, some browsers do not accept var or rgb so it does not return anything (something transparent) this should work since you have a backup color.
When using a valid
var
syntax and the syntax after substitutingvar
is invalid, the value will be the same as usingunset
. This behavior is mentioned in the customer properties spec.As per 3.1 Invalid variables:
And under that section:
Whenever a syntax includes a
var()
, and the syntax is invalid after substituting thevar()
, the value of the declaration will use theunset
value, instead of ignoring the declaration. You can see this behavior in a simpler example: