CSS Cascade Layers (@layer)
TL;DR
Explanation
The CSS cascade determines which rule wins when multiple rules target the same element. Before cascade layers, specificity (ID > class > element) and source order determined the winner — leading to escalating specificity arms races in large teams. @layer (introduced in 2022, supported in all modern browsers) adds a new cascade dimension above specificity: a rule in a later-declared layer wins over all rules in earlier layers, regardless of how specific those earlier rules are. Typical usage: @layer reset, base, components, utilities — utilities always win over components which always win over base, without any need for !important or high-specificity selectors. Third-party CSS can be wrapped in a named layer to ensure your own styles always override it. Unlayered styles (those outside any @layer) have the highest priority — a useful escape hatch. Layers interact with @import and can be nested.
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Declaring layers in the wrong order — the last declared layer has highest priority; @layer reset, utilities gives utilities the win, not reset.
- Mixing layered and unlayered styles unintentionally — styles outside any @layer have higher priority than all layered styles.
- Wrapping everything in a layer including utility overrides — unlayered utilities have highest priority by default, which is usually what you want.
Avoid When
- Avoid cascade layers in small single-file stylesheets where specificity is not yet a problem — the added mental model is not worth it.
- Do not use layers in projects that must support older browsers (pre-2022) without a PostCSS polyfill.
When To Use
- Use @layer in any codebase with third-party CSS (Tailwind base, Bootstrap reset) — wrap third-party styles in a named layer so your styles always win.
- Use layers in design systems to enforce a predictable override hierarchy: reset → base → components → utilities.
- Use them when migrating a legacy codebase with high-specificity selectors — wrap legacy CSS in an early layer so new code can override without specificity gymnastics.
Code Examples
/* Specificity war — escalating selectors to override third-party CSS */
.card { background: white; } /* third-party: specificity 0,1,0 */
div.card.override { background: blue; } /* your fix: 0,2,1 — fragile */
#app div.card { background: blue; } /* next escalation: 1,1,1 */
/* Cascade layers — layer order determines winner, not specificity */
@layer reset, base, components, utilities;
@layer reset {
* { box-sizing: border-box; margin: 0; }
}
@layer components {
.card { background: white; } /* third-party goes here */
}
@layer utilities {
.bg-blue { background: blue; } /* always wins — later layer */
}