CSS Cascade Layers: What @layer Is Actually For
One of the most frustrating parts of CSS is not writing a style. It is finding out why that style did not win.
You write:
.button {
background: black;
}
but another selector is more specific:
.page .content .button {
background: red;
}
So you add another class. Then someone adds !important. After enough time, the stylesheet becomes a small war.
CSS cascade layers give us a better way to manage groups of styles.
The @layer rule has been widely supported since 2022.
The basic idea
You can define layers:
@layer reset, base, components, utilities;
Then put CSS inside them:
@layer reset {
* {
box-sizing: border-box;
}
}
@layer base {
body {
font-family: system-ui, sans-serif;
}
}
@layer components {
.button {
padding: 0.75rem 1rem;
}
}
@layer utilities {
.hidden {
display: none;
}
}
For normal styles, a later layer has more priority than an earlier one.
reset
base
components
utilities
Here, utilities wins over components, which wins over base.
Why this is useful
Without layers, specificity often decides which rule wins.
With layers, you can decide that one whole group should have more priority than another.
@layer third-party, components;
Now:
@layer third-party {
.page .content .button {
background: red;
}
}
@layer components {
.button {
background: black;
}
}
The simpler .button rule can still win because its layer has higher priority.
That is very useful when working with third-party CSS.
A common layer setup
@layer reset, base, layout, components, utilities;
I read that as:
reset → remove browser differences
base → body, headings, links
layout → grids, wrappers, sections
components → buttons, cards, forms
utilities → small helpers
You do not have to use these names.
Put the order near the top
I like defining the layer order at the start:
@layer reset, base, components, utilities;
Then the actual blocks can appear later.
That keeps the priority easy to understand even if CSS is split across several files.
Import a library into a layer
You can place imported CSS into a layer:
@import url("library.css") layer(vendor);
Then:
@layer vendor, site;
Your site styles can live in the later site layer.
@layer site {
.button {
border-radius: 0.5rem;
}
}
You no longer need to make selectors louder just to beat the library.
Unlayered styles
Normal styles outside layers have more priority than normal styles inside named layers.
@layer components {
.button {
background: blue;
}
}
.button {
background: red;
}
The red background wins.
This is useful to know because mixing lots of layered and unlayered CSS without a plan can become confusing.
What about !important?
Important declarations have different layer rules, and their order is reversed.
You do not need to memorize every detail immediately.
The practical lesson is simpler: do not use cascade layers as a reason to add more !important.
The point of layers is to need it less often.
Layers do not replace good selectors
This is still good CSS:
.button {
...
}
You do not need:
body .page main .content .button {
...
}
Layers work best when they let you keep selectors simple.
A small real example
@layer base, components, utilities;
@layer base {
a {
color: blue;
}
}
@layer components {
.button {
display: inline-block;
padding: 0.75rem 1rem;
background: black;
color: white;
}
}
@layer utilities {
.text-red {
color: red;
}
}
Now:
<a class="button text-red" href="#">
Delete
</a>
The utility can override the component text color because utilities comes later.
When I would use layers
They are useful when:
- you import third-party CSS;
- you have a reset;
- your project has several groups of styles;
- specificity is becoming hard to manage;
- utility classes need clear priority;
- a design system is growing.
For a tiny one-page site, you may not need them.
If you want to try cascade layers, start with:
@layer reset, base, components;
Move your reset into reset, normal element styles into base, and reusable UI into components.
CSS specificity problems are often really ordering problems. Cascade layers let you decide that order once instead of fighting it selector by selector.