v130 · css
@media in Nesting
The nested declarations rule's most-bitten real-world case: bare declarations placed after a nested @media block inside a CSS rule. Pre-Chrome 130 parsers hoisted those declarations above the media query, causing cascade-order bugs. Chrome 130 preserves source order by wrapping them in a CSSNestedDeclarations rule.
Feature detection: checking…
The .demo-btn component — same CSS in both light and dark contexts
Light mode
Dark mode
How the CSS is parsed: pre-130 vs Chrome 130+
Pre-Chrome 130 — declarations hoisted
.nested-btn {
/* hoisted HERE by the parser */
border-radius: 4px;
cursor: pointer;
@media (prefers-color-scheme: dark) {
background: #1a1a1a;
}
/* These were actually written here,
but got hoisted above @media */
}
/* hoisted HERE by the parser */
border-radius: 4px;
cursor: pointer;
@media (prefers-color-scheme: dark) {
background: #1a1a1a;
}
/* These were actually written here,
but got hoisted above @media */
}
Chrome 130+ — source order preserved
.nested-btn {
/* stays in place */
@media (prefers-color-scheme: dark) {
background: #1a1a1a;
}
/* CSSNestedDeclarations wraps these */
border-radius: 4px;
cursor: pointer;
}
/* stays in place */
@media (prefers-color-scheme: dark) {
background: #1a1a1a;
}
/* CSSNestedDeclarations wraps these */
border-radius: 4px;
cursor: pointer;
}
Live CSSOM — CSSNestedDeclarations visible in Chrome 130+
Loading…
/*
The pattern that bites developers:
Bare declarations AFTER a nested @media or nested & rule.
*/
.button {
background: white;
color: black;
/* A nested at-rule */
@media (prefers-color-scheme: dark) {
background: #1a1a1a;
color: #f0f0f0;
}
/* Bare declarations AFTER the @media block.
Pre-130: these were hoisted ABOVE the @media rule,
so the @media would always win (or always lose,
depending on specificity and cascade order).
Chrome 130+: wrapped in CSSNestedDeclarations, so they
appear AFTER the @media in the CSSOM —
exactly as written in source. */
border-radius: 4px;
cursor: pointer;
}
/*
Why it matters:
If border-radius was hoisted above @media, then a dark-mode
rule that also set border-radius would always override it.
With CSSNestedDeclarations, declarations stay in their
source position, so the cascade is predictable.
*/