Core concept 01
Cascade Layers
Declare priority order once. Layer order beats specificity between layers — forever eliminating !important wars and load-order fragility.
The problem
CSS specificity is a good rule within a single codebase. But when utilities, components, resets, and third-party styles all compete, the system breaks down. The only escape was increasing specificity or reaching for !important — both of which make the problem worse.
How layers work
The @layer at-rule creates named buckets in the cascade. Within a layer, specificity works exactly as normal. But between layers, the layer order declared at the top of your stylesheet is the authority — not specificity.
The key insight
A class selector in @layer utilities will always beat an ID selector in @layer components — because utilities was declared after components. Layer order is the new specificity.
/* Declare layer order once — first declaration wins */ @layer reset, tokens, base, components, utilities; /* Later layers always win, regardless of selector specificity */ @layer components { #high-specificity.card { color: red; } /* specificity 1,1,0 */ } @layer utilities { .text-blue { color: blue; } /* specificity 0,1,0 — but wins */ }
Try it
The card below has a blue background from a high-specificity #id.class rule inside the unlayered stylesheet. Click the button to add .utility-wins — a lower-specificity class that overrides it because of layer order.
Interactive demo
Demo card
Styled by #layer-demo-card.demo-card
Specificity 1,1,0. In normal CSS this would be nearly unbeatable. Try adding the utility class.
The five-layer stack
This starter declares five layers in css/main.css. The order is fixed — it never changes. Files can be added or imported in any order; the declaration controls everything.
@layer reset, tokens, base, components, utilities; @import "./reset.css"; @import "./tokens.css"; @import "./base.css"; @import "./components.css"; @import "./utilities.css";
Rules to follow
Never write styles outside a layer
Unlayered styles have higher priority than any @layer rule. A style written at the top level of a stylesheet will beat everything in your layer stack.
Anti-pattern
Writing styles outside a layer block — even accidentally — will override your entire layer architecture. Every rule in this project must live inside a named layer.
Never use !important
If you feel the need for !important, you're in the wrong layer. Move the rule to a higher-priority layer and it will win without it.
Layer reference
| Layer | File | Purpose | Add new rules here? |
|---|---|---|---|
reset |
reset.css |
Browser normalisation | Rarely |
tokens |
tokens.css |
All CSS custom properties | For new tokens |
base |
base.css |
Element-level defaults | For new element styles |
components |
components.css |
Named UI patterns | Yes — for new components |
utilities |
utilities.css |
Single-purpose helpers | Yes — for new utilities |