CSS @layer Reference & Generator
Configure cascade layers, visualize priority order, and generate @layer CSS with declaration, block, import, and revert-layer examples
Cascade Layers
Top = lowest priority · Bottom = highest priorityCascade order — left = lowest priority, right = highest
Layer Order Declaration
/* Establish layer order — last listed = highest priority */
@layer reset, base, components, utilities;Generated CSS
/* @import with layer() — assign third-party CSS to a layer */
/* Place @import rules at the top of your stylesheet */
@import url("normalize.css") layer(reset);
/* Establish layer order — last listed = highest priority */
@layer reset, base, components, utilities;
/* reset layer (priority 1/4 — lowest) */
@layer reset {
/* Add your styles here */
}
/* base layer (priority 2/4 — middle) */
@layer base {
/* Add your styles here */
}
/* components layer (priority 3/4 — middle) */
@layer components {
/* Add your styles here */
}
/* utilities layer (priority 4/4 — highest) */
@layer utilities {
/* Add your styles here */
}Your Tailwind utility class .mt-4 should override your component’s margin-top: 0, but it doesn’t because the component selector .card .header has higher specificity. You add !important and it works — until another utility also uses !important and now you’re in a specificity arms race. CSS @layer solves this by letting you declare layer order: utilities always beat components, regardless of selector specificity.
Why This Reference and Generator (Not Just Reading the Spec)
@layer interacts with import order, specificity, !important, nested layers, and anonymous layers in ways that aren’t obvious from the syntax alone. For example, !important rules reverse layer order — an important rule in an earlier layer beats an important rule in a later layer. This reference covers all the edge cases with examples, plus a generator that outputs complete @layer declarations for common architectures (reset → base → components → utilities). Everything runs in your browser.
What Are CSS Cascade Layers?
CSS cascade layers (@layer) give you explicit control over the cascade — the algorithm that determines which CSS rule wins when multiple rules target the same element. Introduced in CSS Cascading and Inheritance Level 5, cascade layers let you group styles into named buckets and declare their priority order once, at the top of your stylesheet.
/* Declare the order: reset → base → components → utilities */
@layer reset, base, components, utilities;
/* Later layers win, regardless of selector specificity */
@layer utilities {
.mt-4 { margin-top: 1rem; } /* beats .card .header { margin-top: 0 } in components */
}
Before @layer, managing the cascade required specificity hacks, !important overuse, or careful source order discipline. Now you can make the priority explicit and predictable.
Three @layer Syntaxes
@layer Declaration (Ordering)
The declaration syntax establishes layer order without attaching any styles. List layer names in priority order — last wins.
/* Low priority → High priority */
@layer reset, base, components, utilities;
- Multiple names, comma-separated
- Must appear before any
@layerblock for those names to control their order - Layers not listed will be appended in the order they are first encountered in source
@layer Block (Attaching Styles)
The block syntax attaches CSS rules to a named layer. Rules in later-declared layers always win over rules in earlier layers, regardless of selector specificity.
@layer base {
a {
color: blue;
text-decoration: underline;
}
}
@layer components {
/* This wins over @layer base rules, even if .btn a has lower specificity */
.btn a {
color: white;
text-decoration: none;
}
}
The same layer name can appear in multiple @layer blocks — rules are merged as if they were written consecutively.
/* Both blocks contribute to the 'base' layer */
@layer base {
* { box-sizing: border-box; }
}
/* Later in the file — still part of 'base' */
@layer base {
body { margin: 0; }
}
@layer Import (Third-Party CSS)
The import syntax assigns all styles from an imported stylesheet to a layer. This is the most powerful pattern for integrating third-party CSS like Normalize.css or Bootstrap into your layer architecture.
/* All normalize.css rules become part of the 'reset' layer */
@import url("normalize.css") layer(reset);
/* Assign to an anonymous layer (cannot be referenced by name) */
@import url("legacy.css") layer();
/* Combine with media condition */
@import url("print.css") layer(print) print;
Important: @import rules must appear at the top of your stylesheet, before any non-@layer rules, @charset excepted.
Layer Ordering and Specificity
The most important mental model: layer order beats selector specificity.
@layer low, high;
@layer high {
/* Class selector — specificity (0,1,0) */
.title { color: green; }
}
@layer low {
/* ID selector — specificity (1,0,0) — but 'low' layer loses */
#main .title { color: red; }
}
/* Result: .title is green — 'high' layer wins despite lower specificity */
Cascade Priority (Lowest → Highest)
| Priority | Source |
|---|---|
| 1 | First-declared @layer (e.g., reset) |
| 2 | Second-declared @layer (e.g., base) |
| … | … |
| n | Last-declared @layer (e.g., utilities) |
| n+1 | Unlayered styles (not inside any @layer) |
Unlayered styles always win over any layered style, regardless of specificity.
How !important Interacts with Layers
!important reverses the layer priority order:
@layer reset, utilities;
@layer reset {
a { color: blue !important; } /* !important in reset WINS over utilities */
}
@layer utilities {
a { color: red !important; } /* !important in later layer LOSES */
}
This is intentional — it lets early layers “lock in” important defaults that later layers cannot accidentally override with !important.
Anonymous Layers
Omitting the layer name in a @layer block creates an anonymous layer. Anonymous layers:
- Cannot be referenced by name in subsequent code
- Cannot be split across multiple blocks (each anonymous
@layer {}is its own unique layer) - Are appended to the layer order in source order
@layer reset, base;
/* Anonymous layer — appended after 'base' */
@layer {
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
}
}
/* Another anonymous layer — separate from the one above */
@layer {
/* These rules have higher priority than the first anonymous layer */
.skip-link { top: 0; }
}
Use case: Wrapping third-party snippets you never want to refer to by name.
Nested Layers
Layers can be nested inside other @layer blocks. Sub-layers follow the same priority rules within their parent scope. Use dot notation to reference nested layers from outside the parent block.
@layer framework {
/* Sub-layer order within 'framework' */
@layer base, components, utilities;
@layer base {
* { box-sizing: border-box; }
}
@layer components {
.btn { padding: 0.5rem 1rem; }
}
}
/* Dot notation: reference 'utilities' inside 'framework' from the outside */
@layer framework.utilities {
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; }
}
Nested Layer Priority
framework.base
< framework.components
< framework.utilities
< (anything outside @layer framework)
This makes nested layers perfect for packaging a complete design system while letting consumers add unlayered overrides that always win.
Reverting Layers with revert-layer
The revert-layer keyword is a CSS-wide value that rolls back a property to the value it would have in the previous cascade layer (or the browser default if there is no previous layer).
@layer base {
a {
color: blue;
font-weight: bold;
text-decoration: underline;
}
}
@layer components {
.nav a {
/* Use the 'base' layer's font-weight (bold), not the browser default */
font-weight: revert-layer;
/* Override just the color */
color: inherit;
}
}
revert-layer is the layered equivalent of revert (which reverts to the browser’s user-agent stylesheet). It is particularly useful in component libraries where you want sub-components to “inherit” the base layer’s intentional defaults rather than fighting them.
Common Patterns
Reset → Base → Components → Utilities
The classic four-layer architecture:
@layer reset, base, components, utilities;
@import url("normalize.css") layer(reset);
@layer base {
:root { --color-primary: #3b82f6; }
body { font-family: system-ui, sans-serif; }
}
@layer components {
.card { border-radius: 0.5rem; padding: 1.5rem; }
.btn { cursor: pointer; }
}
@layer utilities {
.hidden { display: none; }
.sr-only { position: absolute; width: 1px; overflow: hidden; }
}
Design System with Nested Layers
@layer tokens, system, overrides;
@layer system {
@layer base, components;
@layer base {
:root { --spacing-4: 1rem; }
}
@layer components {
.input { padding: var(--spacing-4); border: 1px solid currentColor; }
}
}
/* Consumer overrides always win */
@layer overrides {
.input { border-radius: 0.375rem; }
}
Layering Third-Party Libraries
/* Reset has lowest priority — normalize never overrides your styles */
@import url("https://cdn.example.com/normalize.css") layer(normalize);
/* Bootstrap base goes into its own layer */
@import url("https://cdn.example.com/bootstrap.min.css") layer(bootstrap);
@layer normalize, bootstrap, custom;
/* Your custom styles in the highest layer — always win */
@layer custom {
.btn { border-radius: 0.5rem; } /* Overrides bootstrap's .btn */
}
Browser Support
@layer is supported in all modern browsers since early 2022:
| Browser | @layer support | revert-layer | Nested layers |
|---|---|---|---|
| Chrome | 99+ | 99+ | 99+ |
| Firefox | 97+ | 97+ | 97+ |
| Safari | 15.4+ | 15.4+ | 15.4+ |
| Edge | 99+ | 99+ | 99+ |
| Opera | 85+ | 85+ | 85+ |
Global coverage: ~94% as of early 2026 (can.i.use data). No polyfill is needed for modern web projects. For legacy browser support, ensure your non-layered fallback styles still work on their own.
Frequently Asked Questions
What is the difference between @layer and :where()?
Both reduce effective specificity, but differently. @layer creates explicit priority buckets — a .btn rule in a utilities layer beats a #app .btn rule in a base layer because of layer order. :where() simply zeroes the specificity of its selector argument, so it still participates in the normal specificity comparison. Use @layer for architectural priority control; use :where() when you want a selector to be easily overridable without changing layer structure.
Does @layer work with CSS-in-JS or Tailwind?
Yes. Tailwind CSS v3.3+ supports @layer natively through the @layer utilities and @layer components directives, which map to the built-in Tailwind layer system. For CSS-in-JS libraries, inject layered styles as a string the same way you would inject any global styles — many libraries (Emotion, styled-components) support injection of raw @layer blocks.
Can I use @layer with CSS Modules?
CSS Modules scope class names but do not have a built-in concept of cascade layers. You can write @layer rules inside a .module.css file — the @layer name is global (not scoped) and will be shared across modules. Use unique, prefixed layer names to avoid collisions (e.g., @layer MyComponent.base).
What happens if I declare a layer name that was never used in a block?
The layer name is reserved in the cascade order but contributes no styles. This is perfectly valid — it is common to declare all expected layer names up front (including ones you might add later) to lock in the priority order.
How does @layer interact with @media and @supports?
You can nest @layer inside @media or @supports blocks. The layer is only registered (and its rules applied) when the media or supports condition matches. However, this means the layer may not be registered at all in some environments, so declare your layer order outside condition blocks to ensure consistent ordering.
Should I put everything in layers?
Not necessarily. Styles outside any @layer always win over layered styles. A common pattern is to layer only your “framework” or “library” styles and leave your final overrides as unlayered — they win automatically. Alternatively, go fully layered for maximum explicit control.
Related Tools
- CSS Container Queries Reference — Generate @container CSS for component-level responsive design
- CSS Selector Specificity Calculator — Calculate (a,b,c) specificity scores for selectors
- CSS Media Query Generator — Generate @media rules for standard breakpoints