@layer — Cascade Layers
Take explicit control of the cascade so third-party CSS, resets and components never fight over specificity again.
Cascade layers are one of the most important CSS features of the decade, and they quietly solve a problem that has plagued large codebases forever: specificity wars. The idea is simple — you declare named layers in a deliberate order, and any rule in a later layer beats any rule in an earlier layer, regardless of specificity.
@layer reset, base, components, utilities;
@layer base {
a { color: navy; } /* even this... */
}
@layer components {
.link { color: rebeccapurple; } /* ...loses to this */
}That .link class wins over the element selector and would win even against an ID in an earlier layer, because layer order sits above specificity in the cascade. Specificity still decides ties within a layer.
Why this changes everything
- Import a heavy framework into an early
@layer frameworkand your own@layer appalways wins — no!important, no ID hacks. - Unlayered styles beat all layered styles, so plain author CSS still overrides your layers when you need an escape hatch.
- Declaring the order up front, once, documents your entire architecture in a single line.
Example
When to use it
- A developer places a third-party CSS library in a low-priority @layer so all in-house styles override it without any !important declarations.
- A team declares @layer reset, base, components, utilities at the top of their stylesheet so the precedence order is documented and enforced.
- A developer uses @import url('normalize.css') layer(reset) to add a normalisation stylesheet to the lowest cascade layer.
More examples
Declaring layer order upfront
Declares four layers in priority order so utilities always override components which override base, regardless of source order.
@layer reset, base, components, utilities;
@layer reset {
*, *::before, *::after { box-sizing: border-box; margin: 0; }
}
@layer base {
body { font-family: system-ui, sans-serif; color: #1a1a2e; }
}
@layer utilities {
.mt-4 { margin-top: 4px; }
.hidden { display: none !important; }
}Third-party library in its own layer
Places a third-party stylesheet in the lower external layer so all site-layer rules automatically win by cascade order.
@layer external, site;
@import url('third-party.css') layer(external);
@layer site {
/* Overrides any third-party rule without !important */
.btn {
border-radius: 0;
font-family: inherit;
}
}Unlayered styles always win
Demonstrates that styles written outside any @layer automatically take precedence over all layered styles.
@layer components {
.alert { background: #eef3ff; color: #1a1a2e; }
}
/* No @layer — this wins over any layered rule */
.alert-danger {
background: #fdecea;
color: #c0392b;
}
Discussion