Cascade Layers
Prerequisites: The cascade in depth
Cascade layers (@layer) let you group styles and decide which
group wins — regardless of specificity.
@layer reset, base, components, utilities;
@layer reset {
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; }
}
@layer base {
a { color: #0b57d0; }
h1, h2, h3 { line-height: 1.2; }
}
@layer components {
.card a { color: inherit; }
}
@layer utilities {
.text-red { color: #c62828; }
}
- The first statement fixes the order: later layers win. Here
utilitiesbeatscomponents, which beatsbase. - Inside a layer, normal specificity and order apply.
- Unlayered styles (outside any
@layer) beat all layers.
Specificity doesn't cross layers
<style>
@layer base, components;
@layer components {
.button { color: rgb(0, 128, 0); }
}
@layer base {
#main nav a.button.primary { color: rgb(255, 0, 0); }
}
.note { color: rgb(0, 0, 255); }
@layer components {
p.note.important { color: rgb(255, 165, 0); }
}
</style>
<div id="main"><nav><a class="button primary" href="/">Go</a></nav></div>
<p class="note important">Note</p>
<script>
console.log("button:", getComputedStyle(document.querySelector(".button")).color);
console.log("note:", getComputedStyle(document.querySelector(".note")).color);
</script>
button: rgb(0, 128, 0)
note: rgb(0, 0, 255)
- The button is green: the
componentslayer outranksbase, even though thebaseselector has an id and three classes. - The note is blue: the unlayered
.notebeats the layeredp.note.important.
Layering third-party CSS
@import url("vendor/bootstrap.css") layer(vendor);
@layer vendor, app;
Wrapping a framework in a low layer means your own styles override it without specificity battles.
!important reverses layer order
Important declarations in earlier layers beat important ones in later
layers (just like origins). This lets a reset layer protect rules — for
example, reduced-motion overrides — with !important.
Nested layers and revert-layer
@layer components {
@layer button, card;
}
@layer components.button {
.btn { padding: 0.5rem 1rem; }
}
.special-btn { padding: revert-layer; }
revert-layer rolls a property back to what the previous layers set.
Cascade layers are supported in all major browsers since 2022 (Chrome and
Edge 99, Firefox 97, Safari 15.4). Tailwind CSS v4 uses them for its
theme, base, components, and utilities layers.
Practice
A site imports library.css whose .btn rule has high specificity.
Reorganize so your simple .btn rule wins, without !important or
extra selectors.
Show solution
@layer library, app;
@import url("library.css") layer(library);
@layer app {
.btn { border-radius: 999px; }
}
Even unlayered, your .btn would beat anything in the library layer.
(Note that @import must come before other rules except @layer
statements and @charset.)