Cascade Layers @layer: Specificity Overrides & Unlayered Styles
- Last updated
- Prerequisites:
- CSS specificity and the cascade
- Experience with CSS reset/component stylesheet organization
- css
- cascade
- layers
- specificity
- at-layer
- stylesheet-architecture
Read at your depth
The practical view
@layer lets you group styles into named layers whose priority is decided by declaration order, independent of specificity. @layer reset, base, components, utilities;. Rules in later layers win over earlier layers even with lower specificity. Unlayered styles (written outside any @layer) beat ALL layered styles — a common gotcha. Re-declaring layers in the same order later lets you reorder them: @layer utilities, components; moves utilities last so they win. Use layers to replace specificity wars between reset, third-party CSS, and your components.
The same idea in other frameworks
CSS modules per component + a global @layer setup gives predictable override order for component libraries.Angular's ViewEncapsulation.emulated adds attribute specificity; @layer can tame third-party theme CSS included via styles array.Scoped SFC styles combined with @layer normalize the order between base and component styles.Svelte scoped styles compile to class-hashed selectors; @layer gives deterministic ordering against global resets and UI-kit CSS.Legacy vs modern
Specificity arms race vs cascade layers
Specificity wars need ever-more-specific selectors; @layer decides priority by declared order, so a simple class in a later layer wins cleanly.
body .widget .btn--primary { color: red; } /* ❌ OLD: higher specificity to beat the base rule */@layer base, components, overrides;
@layer overrides { .btn--primary { background: red; } } /* ✅ NEW: wins by layer order */Interview gotchas
Context
This is the most common @layer surprise in production — interviewers test whether you understand that unlayered styles are an implicit final layer, which changes how overrides resolve.
The mechanical answer
The cascade assigns unlayered author styles the highest layer priority — as if they belonged to an implicit layer declared after all explicit layers. That means any style written outside @layer (which includes most legacy CSS) wins over layered rules of equal specificity regardless of the @layer order. During migration this is usually desirable (your existing overrides keep winning), but it silently defeats attempts to make a new utility layer beat legacy component styles until you move the legacy styles into a layer. The fix is to wrap legacy stylesheets (e.g. via @import url(...) layer(legacy)) so they participate in the layer order instead of sitting at the top.
Trap
The naive answer is 'unlayered styles lose to layered ones'. They win, because unlayered is the implicit last layer. Another trap: assuming @layer resets specificity entirely — within the same layer, specificity and source order still apply normally. Candidates who mention the implicit-final-layer behavior show they have actually shipped layers.
Context
This probes the more advanced layer mechanics — layer trees and the way declaration order across stylesheets composes — which trips up architects designing design-system CSS.
The mechanical answer
Named layers form a tree via dot syntax: @layer components.buttons and @layer components.forms both nest under components. Comparison between two layers walks the path: shallower layers come first, and within the same parent, siblings compare by their declared order. Repeated @layer statements without a body (e.g. @layer a, b; then later @layer a, b;) do not reset the order — they add to it, and the final order is the first-declared sequence for each name. This lets you define the order in a bootstrap file and then add rules to layers anywhere. Nested layers follow the same index comparison recursively, so a rule in components.buttons beats components.forms only if buttons was declared after forms.
Trap
The naive answer is 're-declaring @layer reorders the layers'. The order is set by the first declaration of each name; later @layer statements only append rules to existing layers. Another trap: thinking specificity leaks across nested layers — the layer index is compared first, so a 0-0-0 rule in a deeper/later layer can still beat a high-specificity rule in an earlier layer. Candidates who describe the layer tree and first-declaration ordering show real architectural understanding.