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 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?
When using a valid var syntax and the syntax after substituting var is invalid, the value will be the same as using unset. This behavior is mentioned in the customer properties spec.
As per 3.1 Invalid variables:
A declaration can be invalid at computed-value time if it contains a var() that references a custom property with the guaranteed-invalid value, as explained above, or if it uses a valid custom property, but the property value, after substituting its var() functions, is invalid. When this happens, the computed value is one of the following depending on the property’s type:
And under that section:
Either the property’s inherited value or its initial value depending on whether the property is inherited or not, respectively, as if the property’s value had been specified as the unset keyword.
With the reasoning of why it can't fall back to other declarations:
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.
You can see this behavior in a simpler example, where the value results like unset:
body {
  color: green;
}
.example {
  --bg-red: red;
  color: blue;
  color: var(--bg-red) I am a invalid syntax;
}
<div class="example">test</div>
These are the only 3 ways I can think of to provide fallbacks for unsupported value syntax that includes the use of var(), ordered by how widely supported they are.
background-color is not inheritable, and has major drawback of the need to modify the parent element:.parent {
  color: blue;
}
.example {
  --bg-color: red;
  color: rgb(from var(--bg-color) r g b / 0.5);
}
<div class="parent">
  <div class="example">test</div>
</div>
var in the supports-condition:/*First Method*/
.example {
  --bg-color: red;
  background-color: darkgray;
  background-color: var(--bg-color);
}
@supports (background-color: rgb(from red r g b / 0.5)) {
  .example {
    background-color: rgb(from var(--bg-color) r g b / 0.5);
  }
}
<div class="example">example 1</div>
@property to define the initial-value as the fallback value. This has the major drawback that the initail value must be hard coded:@property --bg-relative {
  syntax: "<color>";
  inherits: false;
  initial-value: blue;
}
.example {
  --bg-color: red;
  --bg-relative: rgb(from var(--bg-color) r g b / 0.5);
  background-color: var(--bg-relative);
}
<div class="example">Example 2</div>
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