CSS Cascade Layers
CSS cascade layers give you explicit control over the order of precedence between groups of styles. Instead of fighting specificity to override a third-party library or struggling with rule order, you declare named layers and decide upfront which layer wins when there is a conflict.
The Problem Cascade Layers Solve
DIAGRAM — The classic override problem:
You use a CSS library with this rule:
.btn { background: blue; } /* specificity: 010 */
Your own style:
.btn { background: red; } /* specificity: 010 */
Both have the same specificity.
Order decides — and the library loads before your code.
Result: button stays blue.
Fix attempt:
button.btn { background: red; } /* specificity: 011 — wins */
Later the library adds:
.wrapper .btn { background: blue; } /* specificity: 020 — wins again! */
You keep bumping specificity. It never ends.
DIAGRAM — With cascade layers:
@layer base, components, utilities;
@layer base {
.btn { background: blue; } /* in "base" layer */
}
/* Your styles in "utilities" — declared AFTER base, so they win */
@layer utilities {
.btn { background: red; } /* wins! Layer order trumps specificity */
}
No specificity war. The layer hierarchy is clear and permanent.
Declaring Layers
Declare the layer order at the top of your stylesheet using a single @layer statement with the layer names. The order you declare here determines which layer wins: layers declared later win over layers declared earlier.
/* Declare order first — later = higher priority */
@layer reset, base, components, utilities;
DIAGRAM — Layer priority:
@layer reset, base, components, utilities;
Priority (lowest to highest):
reset ← lowest (easiest to override)
base ←
components ←
utilities ← highest (hardest to override)
Adding Styles to a Layer
@layer reset {
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
}
@layer base {
body {
font-family: sans-serif;
line-height: 1.6;
color: #333;
}
a { color: blue; }
}
@layer components {
.btn {
display: inline-block;
padding: 10px 24px;
background: #3498db;
color: white;
border-radius: 6px;
}
.card {
background: white;
border-radius: 8px;
padding: 20px;
}
}
@layer utilities {
.text-red { color: red; }
.mt-auto { margin-top: auto; }
.hidden { display: none; }
}
How Layer Priority Works
@layer reset, base, components, utilities;
@layer components {
.btn { background: blue; } /* specificity: 010 */
}
@layer utilities {
.btn { background: red; } /* specificity: 010 */
}
Result: RED — because "utilities" is declared after "components"
Layer order beats specificity!
/* Even a lower-specificity rule in a higher layer wins */
@layer components {
.big-wrapper .side-panel .btn { background: blue; } /* 030 */
}
@layer utilities {
.btn { background: red; } /* 010 — wins anyway! */
}
Result: RED — utilities layer wins, even with lower specificity
Unlayered Styles Always Win
Styles NOT inside any layer always win over all layered styles, regardless of specificity.
@layer utilities {
.btn { background: red !important; }
}
/* This is outside any layer */
.btn { background: green; }
Result: GREEN — unlayered styles beat all layers
DIAGRAM — Full priority order (lowest to highest):
1. Layer "reset" styles
2. Layer "base" styles
3. Layer "components" styles
4. Layer "utilities" styles
5. Unlayered styles ← always wins over any layer
6. !important (reversed order for !important rules)
Importing Third-Party CSS into a Layer
This is one of the most practical uses. You put a library's CSS into a low-priority layer so your styles always override it without specificity battles.
/* Put Bootstrap into a "framework" layer */
@layer framework {
@import url("bootstrap.min.css");
}
/* Declare your app layers above "framework" */
@layer framework, app;
/* Your styles win over Bootstrap automatically */
@layer app {
.btn { background: purple; } /* wins over Bootstrap's .btn */
}
Nested Layers
Layers can be nested inside other layers for finer organization.
@layer components {
@layer buttons {
.btn { padding: 10px 20px; }
}
@layer cards {
.card { border-radius: 8px; }
}
}
/* Reference nested layers with dot notation */
@layer components.buttons {
.btn-sm { padding: 6px 12px; }
}
Anonymous Layers
You can create a layer without naming it. Anonymous layers cannot be referenced again — they are useful for one-time imports of third-party code.
@layer {
/* These styles are in an anonymous layer */
/* They cannot be added to later */
.legacy-class { color: gray; }
}
Layers with @import
/* Import and assign to a layer in one line */
@import url("normalize.css") layer(reset);
@import url("theme.css") layer(base);
A Complete Layer Architecture
/* 1. Declare all layers in order (lowest priority first) */
@layer reset, tokens, base, layout, components, utilities;
/* 2. Reset browser defaults */
@layer reset {
*, *::before, *::after { box-sizing: border-box; margin: 0; }
}
/* 3. Design tokens (CSS variables) */
@layer tokens {
:root {
--color-primary: #3498db;
--space-md: 16px;
}
}
/* 4. Base element styles */
@layer base {
body { font-family: sans-serif; }
h1 { font-size: 2rem; }
a { color: var(--color-primary); }
}
/* 5. Page-level layout */
@layer layout {
.container { max-width: 1200px; margin-inline: auto; }
.grid-3col { display: grid; grid-template-columns: repeat(3, 1fr); }
}
/* 6. UI components */
@layer components {
.btn { padding: var(--space-md); background: var(--color-primary); }
.card { padding: var(--space-md); border-radius: 8px; }
}
/* 7. Utility classes — override anything */
@layer utilities {
.hidden { display: none; }
.flex { display: flex; }
}
Browser Support
Cascade layers are supported in all modern browsers — Chrome 99+, Firefox 97+, Safari 15.4+. For older browser support, a PostCSS plugin can polyfill the behavior.
When to Use Layers
| Situation | Use Layers? |
|---|---|
| Using a third-party CSS library | Yes — put library in a low-priority layer |
| Large team project | Yes — layers enforce consistent override rules |
| Design system | Yes — separate tokens, base, and components |
| Small personal project | Optional — overkill for simple sites |
Cascade layers make CSS architecture explicit and predictable. Define the hierarchy once, follow it consistently, and the specificity wars that plague large stylesheets become a thing of the past.
