Cascade Layers @layer
Use @layer to order reset, base, components, and utilities so specificity wars lose — layer priority, unlayered CSS, and !important.
- css
- cascade-layers
- architecture
Cascade layers (@layer) let you declare priority buckets for whole groups of rules. A utility in a later layer can beat a component selector even when the component’s selector is “more specific.” That is the point: stop climbing specificity to win overrides.
Docs: MDN cascade layers, @layer.
Declare order first
@layer reset, base, components, utilities;
Later names in that list win over earlier ones for normal (non-!important) declarations when both set the same property.
@layer reset {
* {
margin: 0;
}
}
@layer components {
.button {
background: var(--brand);
color: white;
padding: 0.5rem 1rem;
}
}
@layer utilities {
.bg-transparent {
background: transparent;
}
}
<button type="button" class="button bg-transparent">Ghost</button>
.bg-transparent wins on background even though both are single classes — layer order, not selector weight, decided it.
Unlayered CSS is a boss fight
Any styles outside @layer act like a final layer higher than layered normal styles (for normal declarations). That surprises people who append a “quick fix” at the bottom of a file:
@layer components {
.card {
padding: 1rem;
}
}
/* Unlayered — beats layered components */
.card {
padding: 2rem;
}
Team convention: either put everything in layers, or treat unlayered as emergency-only.
Nested and anonymous layers
@layer framework {
@layer components {
.btn { }
}
}
/* Referenced later as framework.components */
@layer {
/* anonymous — order is first-appearance */
}
Prefer named layers and one explicit order list at the top of the entry CSS.
Interaction with specificity and importance
For competing declarations, the cascade roughly considers:
- Origin & importance
- Layer (for that origin/importance)
- Specificity
- Order
Within the same layer, specificity and source order still apply.
@layer components {
.card.title { color: blue; } /* higher specificity */
.title { color: red; }
}
/* .card.title wins inside the layer */
!important reverses layer order among important declarations (important in earlier layers can win). That is hard to reason about — avoid !important except rare utilities or third-party overrides.
Practical architecture
@layer reset, tokens, base, layout, components, utilities;
@layer tokens {
:root {
--space-2: 0.5rem;
--brand: #0b6bcb;
}
}
@layer base {
body {
font-family: system-ui, sans-serif;
line-height: 1.5;
}
}
@layer utilities {
.sr-only { /* … */ }
.mt-2 { margin-top: var(--space-2); }
}
Frameworks (Bootstrap layers, Tailwind’s layered build, design-system packages) increasingly ship this way so host apps can slot overrides into a known layer.
Importing into layers
@import url("reset.css") layer(reset);
@import url("buttons.css") layer(components);
Useful when third-party CSS shouldn’t stomp your utilities — wrap the import in a low layer.
Interview out-loud
“@layer groups rules into ordered buckets. Later layers override earlier ones regardless of specificity for normal declarations. Unlayered CSS beats layered CSS, so I keep a single ordered list like reset → base → components → utilities and avoid stray unlayered fixes. !important inverts layer priority and I treat it as a last resort.”
Footguns
- Forgetting the initial order list and relying on first-appearance order only.
- Leaving debug CSS unlayered.
- Using layers and ultra-specific selectors — still a mess inside a layer.
- Assuming layers replace cascade knowledge — they don’t; they reorder a step.
- Shipping critical CSS without the layer order preamble.
Related
- Cascade & specificity
- CSS specificity deep dive
- CSS reset vs normalize vs layer
- CSS architecture ITCSS overview
Further reading
Related guides
- BEM Naming MethodologyBlock, Element, Modifier naming for CSS — how it limits specificity wars, what to name, and when utility or CSS modules beat strict BEM.
- CSS Architecture ITCSS OverviewITCSS inverted triangle — settings through utilities — how layer order reduces specificity wars in large stylesheets.
- Utility-First CSS TradeoffsUtility-first (Tailwind-style) pros and cons — speed, consistency, HTML noise, design-token discipline, and when components still win.
- Accent Color and Form ControlsUse accent-color to theme native checkboxes, radios, ranges, and progress — what it paints, what it skips, and when to custom-style instead.
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.