CSS Layers (@layer)
CSS Cascade Layers, introduced by the @layer at-rule, provide a powerful mechanism for organizing CSS and controlling the cascade more predictably. They solve a long-standing problem in large-scale CSS projects: how to manage specificity conflicts between different sources of styles (e.g., framework, base, components, and utilities).
The Core Concept: Styles within a higher-priority layer will always win over styles in a lower-priority layer, regardless of the selector's specificity within those layers.
1. The Cascade Layer Order
The final result of a style depends on the following order of precedence, from lowest to highest:
- User Agent Styles (Browser defaults)
- Author Styles (Your written CSS)
- Normal styles in the order they appear (without
@layer) - Styles within layers (Layer order is custom, see below)
- Normal styles in the order they appear (without
- User Styles (
!importantrules) - Author Styles (
!importantrules) - User Agent Styles (
!importantrules)
Within the "Styles within layers" category, the layer order is defined by you.
Layer Precedence Rule
When using layers, the precedence is determined by the layer order defined at the top of your stylesheet:
- Earlier layers have lower priority.
- Later layers have higher priority.
Crucially: Styles outside any layer are treated as having the highest priority among all normal author styles.
2. Defining and Ordering Layers
You define the order of your layers using a single @layer statement at the top of your CSS file.
2.1. Defining the Order
/* 1. Define the layer order (Lowest to Highest Precedence) */
@layer reset, framework, base, components, utilities;
Based on this order:
resetstyles have the lowest priority.utilitiesstyles have the highest priority.
2.2. Creating Layer Blocks
You then wrap your styles in named @layer blocks.
/* -- 1. Reset Layer (Lowest Priority) -- */
@layer reset {
/* This style will lose to any style in a higher layer, even if the selector is less specific. */
* {
margin: 0;
padding: 0;
}
}
/* -- 2. Components Layer (Mid Priority) -- */
@layer components {
/* Example: A component style */
.button {
background-color: var(--theme-color);
padding: 10px 20px;
}
}
/* -- 3. Utilities Layer (Highest Layer Priority) -- */
@layer utilities {
/* This utility class will override .button's background, even though it's less specific */
.u-red {
background-color: red;
}
}
If both .button and .u-red target the same property on the same element, the style from the utilities layer wins because utilities was defined after components in the initial @layer order.
3. Unlayered Styles (The Exception)
Styles that are not included in any @layer block are considered unlayered styles. They have a higher precedence than all layered styles.
This is a deliberate feature, ensuring that quick, necessary overrides or custom changes that don't belong in a specific layer can still win without resorting to !important.
| Style Type | Priority (Highest to Lowest) |
|---|---|
!important (Author) | Highest |
| Unlayered Styles | High (Wins over all layered styles) |
| Layered Styles | Mid (Order is determined by @layer definition) |
| Normal Specificity | Lowest (Standard specificity rules apply within a layer) |
4. Practical Use Case: Framework Integration
Layers are essential when combining external CSS (like a framework) with your custom styles.
Goal: Ensure your custom component styles can easily override framework defaults without needing complex selectors.
/* 1. Define the Order */
/* Framework is low priority; components are high priority */
@layer framework, components, utilities;
/* 2. Import the Framework (e.g., a simple UI kit) */
@import url('external-ui-framework.css') layer(framework);
/* 3. Write Custom Styles */
@layer components {
/* Even if .fw-btn-primary has high specificity in the framework,
this style will win because the 'components' layer is defined later. */
.fw-btn-primary {
background-color: darkgreen; /* Your custom color wins */
border-radius: 20px;
}
}
Interactive CSS Layers Demo
This demo illustrates layer precedence: the Utility layer is defined later than the Component layer, so the Utility's background color always wins, despite the Component selector being equally specific.