What does the CSS @layer at-rule do, and how does a layer's position affect which declaration wins?
answer
- a sort step above specificity
- whole buckets of CSS, ordered
- later-declared bucket wins
- an id in an early layer still loses
- specificity only breaks ties inside one
basics
~20 s@layer groups CSS rules into named layers that the cascade compares before it looks at specificity. A declaration in a later-declared layer beats one in an earlier layer, even when the earlier selector is far more specific.
solid answer
~40 s`@layer` lets you split a stylesheet into ordered buckets — typically something like `@layer reset, base, components, utilities;` — and the cascade uses that order as a sort step that sits **above** specificity. So a plain `.btn { color: blue }` in the `utilities` layer beats `#header .btn { color: red }` in the `components` layer, because the layer comparison is decided before specificity is ever consulted. Specificity has not gone away; it is still what breaks ties *inside* a single layer, and source order breaks ties after that. The practical value is that you stop escalating selectors: instead of adding an id or `!important` to win, you put the rule in a later layer. Layers have been supported across Chrome, Edge, Firefox and Safari since early 2022.
code
css · 9 lines@layer components, utilities;
@layer components {
#page .btn { color: red; }
}
@layer utilities {
.text-blue { color: blue; }
}go deeper
Be ready to say what @layer is for in one sentence and show the ordering statement @layer reset, base, components;. Know that a rule in a later layer wins even if its selector is simpler.
Explain the sort sequence: layer order is compared before specificity, and specificity only resolves conflicts inside one layer. Be able to predict the winner from a short snippet with two layers.
Show judgment about layer architecture — which buckets a codebase needs, why utilities go last, and how layers replace the specificity arms race and stray !important in day-to-day review.
Own the tradeoff: layers make override rules explicit and file-order-independent, but they add a convention every contributor must learn, and a wrong layer assignment fails silently. Argue when that cost is worth paying.
## The problem layers solve Before cascade layers, the only levers for making one rule beat another were specificity (add a class, an id, repeat the class) and `!important`. Both are one-way ratchets: once a codebase has `#app .card .title` in it, every later rule that wants to win has to be at least that specific, and the numbers only climb. Cascade layers add a dimension that is entirely independent of the selector you wrote. ## What the at-rule does `@layer` declares a named bucket of rules. Two forms matter: ```css /* 1. a statement that only establishes order */ @layer reset, base, components, utilities; /* 2. a block that puts rules into a layer */ @layer components { .card { padding: 1rem; border: 1px solid gray; } } ``` The statement form contains no rules — it just fixes the order of the names. The block form assigns rules to a layer. You can also write an anonymous layer, `@layer { ... }`, which gets a position but no name. ## Layer order is its own sort step When two declarations set the same property on the same element, the browser walks a sequence of comparisons. Among normal (non-`!important`) author declarations, the comparison relevant here runs **layer order first, then specificity, then source order**. That ordering is the whole point: a later layer wins outright, and the specificity of the two selectors is never compared at all. ```css @layer components, utilities; @layer components { #page .btn { color: red; } /* specificity (1,1,0) */ } @layer utilities { .text-blue { color: blue; } /* specificity (0,1,0) */ } ``` An element matching both is blue. The id selector loses because `utilities` was declared after `components`. Reverse the two names in the first line and the same element turns red — you changed the outcome without touching a single selector. ## Specificity is not disabled A common misreading is that layers replace specificity or zero it out. They do not. Inside `utilities`, if `.text-blue` and `#page .text-blue` both matched, the id selector would still win: specificity is computed exactly as it always was and used to resolve conflicts *within* a layer. Layers only decide which layer's declaration is considered the winner when the layers differ. (Zeroing specificity is what the `:where()` pseudo-class does, and that is a different tool.) ## What layers do not reach Layers sort declarations *within* an origin — they do not let author CSS outrank a user's own styles, and they do not touch the user-agent stylesheet's role. The `style` attribute on an element is also unaffected: an inline `style="color: green"` beats every normal author declaration, layered or not. And `!important` does not simply follow layer order — it inverts it, which is a separate rule worth learning on its own. ## How teams actually use it The conventional pattern is a single ordering statement at the top of the entry stylesheet, so anyone reading the file learns the architecture in one line: ```css @layer reset, vendor, base, layout, components, utilities; ``` Everything after that goes into one of those buckets, and the question "why did my rule not apply" gains a cheap first answer: check which layer each rule is in. Utilities placed last win over components by construction, which is exactly the behaviour utility classes need and the reason they historically shipped with `!important`. ## Support Cascade layers shipped in Chrome and Edge 99, Firefox 97, and Safari 15.4 — all in the first quarter of 2022 — so they are safe in any project that is not supporting pre-2022 browsers. There is no partial-support story to reason about: a browser either understands `@layer` or drops the block entirely, which is worth remembering because an old browser ignoring a `@layer` block means those rules simply do not exist for it, not that they fall back to being unlayered. ## The one-line summary A layer is a promotion mechanism for whole groups of CSS. You move a rule up by moving its layer, not by making its selector uglier.
- Does moving a rule into a layer change the specificity of its selector?No. Specificity is computed from the selector exactly as it always is, and layers never modify it. The difference is when it is consulted: the browser compares layer order first, and only falls back to specificity when both declarations sit in the same layer. If you actually want a selector to score zero, that is `:where()`, not `@layer`.
- Where does an inline style attribute sit relative to layered rules?Above all of them. A declaration in an element's `style` attribute beats every normal author declaration regardless of which layer it is in, because layers sort rules within the author origin and the style attribute is handled outside that comparison. Layers are therefore no help against inline styles injected by a script or a third-party widget.
- What happens in a browser that does not understand @layer?It fails to parse the at-rule and discards the whole block, so those rules do not apply at all — they do not degrade into unlayered styles. That is only a concern for browsers older than early 2022; since then every major engine supports it, so no fallback strategy is normally needed.
Think of layers as league divisions: a mediocre team in the top division still ranks above the best team in the division below, and the head-to-head record (specificity) only settles matches inside the same division.
saying these in an interview costs you the question
- Says layers change the specificity of the selectors inside them
- Claims an id selector always wins no matter the layer
- Thinks @layer is just grouping with no cascade effect
- Believes layers let author CSS outrank inline style attributes
- Assumes specificity is compared first and layers break ties