@supports Lies: When CSS Says 'Yes' but Browsers Say 'LOL No'
Source: Dev.to
Introduction
According to the CSS specification, the @supports at‑rule must be placed at the top level or nested inside another conditional‑group at‑rule. However, browsers also allow code like this (which, at least in theory, is not valid):
.my-class {
@supports (property: value) {
/* … */
}
}
This behavior is confusing. Browsers could either ignore the nested @supports entirely (or always execute it, since browsers are often forgiving with HTML and CSS), or they could apply it relative to the rule it is nested in. Applying it as if it were at the root level while visually nesting it inside a selector can be misleading.
Example
li::marker {
@supports (content: " - ") {
content: " - ";
color: red;
}
}
- Chrome, Safari, and Firefox support
::marker, and they all supportcontent: " - ". - Safari does not support
contentinside::marker.
With the code above:
- Chrome and Firefox render a red “ - ”.
- Safari renders a red circle instead.
The confusing part is that the @supports condition succeeds even though the declaration is not actually supported in that specific context.
Why This Happens
The issue is less about browsers “moving” (or more accurately “parsing”) nested @supports rules to the top‑level context, and more about how @supports itself is defined. The feature check determines whether a declaration is generally valid, not whether it is valid for a specific selector or pseudo‑element context.
Possible Solutions
Extend @supports with Context‑Aware Checks
Introduce a new operator or function so that @supports can validate combinations rather than independent features. For example:
@supports selector(::marker) and (content: " - ")
or
@supports selector(::marker) xand (content: " - ")
or even a rule‑based check:
@supports rule(::marker { content: " - " })
These would allow testing whether a declaration truly works within a given rendering context, instead of only checking if the syntax is recognized.
Make Browsers Less Forgiving
A less ideal approach would be for browsers to never execute nested @supports rules. However, this would break existing code that relies on the current forgiving behavior.
Workarounds
Container queries and style queries can sometimes be used as a workaround, but they currently have partial support and can only check for custom properties, not arbitrary declarations. While helpful in some cases, they do not eliminate the misleading or limited nature of nested @supports.