CSS layer() Function
The CSS layer() function assigns an imported stylesheet to a named cascade layer using the @import at-rule.
Cascade layers organize styles into groups with a defined priority. The layer() function makes it possible to place external stylesheets into those groups, helping control which styles take precedence without relying entirely on selector specificity.
Syntax
@import "stylesheet.css" layer(layer-name);
@import url("stylesheet.css") layer(layer-name);
The layer() function follows the stylesheet URL in an @import rule.
For example:
@import "buttons.css" layer(components);
This imports the rules from buttons.css into the named cascade layer components.
Additional examples:
@import "reset.css" layer(reset);
@import "layout.css" layer(layout);
@import "theme.css" layer(theme);
@import "buttons.css" layer(components.buttons);
The function accepts one layer name, which may contain dot-separated identifiers for nested layers.
To create an anonymous layer, use the layer keyword without parentheses:
@import "utilities.css" layer;
The layer() function itself requires a valid layer name. Empty parentheses are not valid.
Parameters
The layer() function accepts one required parameter.
| Parameter | Description | Required |
|---|---|---|
layer-name |
Identifies the named cascade layer that receives the imported stylesheet. | Yes |
A layer name consists of a CSS identifier or multiple identifiers separated by periods.
For example:
layer(reset)
layer(components)
layer(framework.buttons)
layer(framework.theme.dark)
Each period separates a parent layer from a nested sublayer.
Layer names are case-sensitive. For example, layer(Theme) and layer(theme) identify different layers.
Spaces cannot replace the periods between nested layer names.
How It Works
The layer() function tells the browser which cascade layer should contain the rules from an imported stylesheet.
For example:
@import "components.css" layer(components);
When the browser processes this rule:
- It identifies the external stylesheet.
- It identifies or creates the named
componentslayer. - It places the imported stylesheet's rules into that layer.
- It applies cascade layer priority when resolving competing declarations.
If the named layer already exists, the imported rules are added to that layer.
If the layer has not been declared, the import creates it.
The function does not return a CSS property value. It is part of the @import at-rule syntax.
Named Layers
A named cascade layer groups related CSS rules under a reusable identifier.
For example:
@import "reset.css" layer(reset);
@import "components.css" layer(components);
@import "utilities.css" layer(utilities);
These imports create or populate three named layers.
Named layers can also be declared before importing styles:
@layer reset, components, utilities;
@import "reset.css" layer(reset);
@import "components.css" layer(components);
@import "utilities.css" layer(utilities);
The @layer statement establishes the layer order before the stylesheets are imported.
This makes the intended priority easier to understand and maintain.
Layer names are chosen by the developer. Names such as reset, base, components, and utilities are conventions, not reserved CSS keywords.
Anonymous Layers
An anonymous layer is a cascade layer without a reusable name.
To import a stylesheet into an anonymous layer, use the layer keyword:
@import "third-party.css" layer;
This creates a new anonymous cascade layer for the imported stylesheet.
Each anonymous layer is distinct and cannot be referenced later by a layer name.
For example:
@import "library-a.css" layer;
@import "library-b.css" layer;
These imports create two separate anonymous layers.
Use named layers when multiple stylesheets need to share a layer or when the layer should be referenced elsewhere.
The syntax layer() with empty parentheses does not create an anonymous layer.
Layer Order
Cascade layer order determines the priority of declarations from different layers.
For normal declarations of the same origin, later layers have higher priority than earlier layers.
For example:
@layer reset, base, components, utilities;
The normal declaration priority increases in this order:
| Layer | Normal Declaration Priority |
|---|---|
reset | Lowest |
base | Higher |
components | Higher |
utilities | Highest among these layers |
The stylesheets can then be imported into the declared layers:
@layer reset, base, components, utilities;
@import "reset.css" layer(reset);
@import "base.css" layer(base);
@import "components.css" layer(components);
@import "utilities.css" layer(utilities);
The first declaration of the layer order establishes its relative priority. Later references to those names do not rearrange existing layers.
Layer order is considered before selector specificity when comparing normal declarations in different layers of the same origin.
Nested Layers
Nested layers organize cascade layers into parent and child groups.
The layer() function uses periods to identify nested layers.
For example:
@import "buttons.css" layer(components.buttons);
@import "forms.css" layer(components.forms);
@import "cards.css" layer(components.cards);
These imports create three sublayers inside the components layer.
Nested layers can also be declared explicitly:
@layer components {
@layer buttons, forms, cards;
}
The corresponding imports can then reference the complete layer paths:
@import "buttons.css" layer(components.buttons);
@import "forms.css" layer(components.forms);
@import "cards.css" layer(components.cards);
Each sublayer has its own position within the parent layer's cascade order.
Nested layers are useful for organizing larger CSS projects without creating unrelated top-level layer names.
Multiple Imports
Multiple stylesheets can be imported into the same named layer.
For example:
@import "buttons.css" layer(components);
@import "forms.css" layer(components);
@import "cards.css" layer(components);
All three stylesheets contribute rules to the components layer.
When competing declarations belong to the same layer, the normal cascade rules, including specificity and source order, determine which declaration wins.
For example, if both imported stylesheets contain an equally specific rule for the same property, the later applicable declaration normally takes precedence.
Importing into an existing layer does not create a new layer or change that layer's original priority.
Unlayered Styles
CSS rules outside explicit cascade layers are called unlayered styles.
For normal author declarations, unlayered styles have higher cascade priority than declarations in named or anonymous author layers.
For example:
@layer components {
.button {
background-color: blue;
}
}
.button {
background-color: green;
}
The button appears green because the unlayered declaration has higher priority.
This remains true even when the layered selector is more specific.
For example:
@layer components {
#main .button {
background-color: blue;
}
}
.button {
background-color: green;
}
Assuming both selectors match the same element, the unlayered green declaration wins.
This behavior applies to normal declarations. Important declarations follow a different layer priority order.
Layer Priority and Specificity
Cascade layers help reduce conflicts caused by increasingly specific selectors.
For example:
@layer base, components;
@layer base {
#main .button {
color: blue;
}
}
@layer components {
.button {
color: red;
}
}
When both selectors match, the button text appears red.
The components layer has higher priority for normal declarations, even though the selector in the base layer is more specific.
Within a single layer, specificity still matters:
@layer components {
.button {
color: blue;
}
.panel .button {
color: red;
}
}
The more specific selector wins when both rules apply and other cascade factors are equal.
Layers provide an additional level of control rather than replacing the CSS cascade.
Important Declarations
The !important flag reverses the normal priority order of cascade layers within the same origin.
For normal declarations, later layers have higher priority. For important declarations, earlier layers have higher priority.
For example:
@layer base, components;
@layer base {
.button {
color: blue !important;
}
}
@layer components {
.button {
color: red !important;
}
}
The button text appears blue because the earlier base layer has higher priority for important declarations.
Important declarations in explicit layers also take precedence over important declarations outside those layers at the same origin.
This reversal is intentional and helps protect foundational styles when necessary.
For most ordinary styling, establish a clear layer order and avoid unnecessary use of !important.
Conditional Imports
The layer() function can be combined with media queries and feature conditions in an @import rule.
For example:
@import "print.css" layer(print) print;
This imports the stylesheet into the print layer when the print media condition applies.
Another example uses a viewport condition:
@import "desktop.css" layer(layout) screen and (min-width: 768px);
The imported rules apply only when the media condition matches.
The supports() import condition can also be used:
@import "grid.css" layer(layout) supports(display: grid);
This imports the stylesheet when the browser supports CSS Grid layout.
When both a feature condition and a media query are present, the supports() condition comes before the media query:
@import "advanced.css" layer(layout) supports(display: grid) screen and (min-width: 768px);
These conditions control whether the imported styles apply. They do not change the fundamental priority rules of cascade layers.
Import Placement
The @import at-rule has placement restrictions within a stylesheet.
Imports must appear before ordinary style rules and most other at-rules.
For example:
@layer reset, base, components;
@import "reset.css" layer(reset);
@import "base.css" layer(base);
@import "components.css" layer(components);
body {
margin: 0;
}
This is valid because the imports appear before the ordinary body rule.
The following placement is invalid:
body {
margin: 0;
}
@import "components.css" layer(components);
The import is ignored because it appears after an ordinary style rule.
Layer-order statements such as @layer reset, base; may appear before imports, but @layer blocks containing rules cannot precede an @import rule.
Place layer declarations and imports near the beginning of the stylesheet to keep their order clear.
layer() vs. @layer
The layer() function and the @layer at-rule are related but have different roles.
| Feature | layer() | @layer |
|---|---|---|
| Type | At-rule function | CSS at-rule |
| Purpose | Assign an imported stylesheet to a named layer. | Declare layers, establish their order, or contain CSS rules. |
| Used with | @import |
Layer declarations and rule blocks |
| Imports a stylesheet | Used as part of an import | No |
| Supports nested names | Yes | Yes |
For example, layer() assigns an external stylesheet to a layer:
@import "buttons.css" layer(components);
The @layer at-rule can define styles directly:
@layer components {
.button {
background-color: blue;
}
}
Both methods contribute to the same cascade layer when they reference the same layer name.
Use @layer to define layer order and local rules, and layer() to organize imported stylesheets.
Example
This example demonstrates how cascade layer priority determines the final button color.
The example uses @layer blocks to demonstrate the same layer precedence that applies when stylesheets are imported using layer().
HTML:
<div class="layer-demo">
<button class="layer-demo-button" type="button">Layered Button</button>
<p>The components layer overrides the base layer.</p>
</div>
CSS:
@layer kd-layer-demo-base, kd-layer-demo-components;
@layer kd-layer-demo-base {
.layer-demo .layer-demo-button {
background-color: #0066cc;
color: #fff;
}
}
@layer kd-layer-demo-components {
.layer-demo-button {
background-color: #198754;
color: #fff;
}
}
.layer-demo {
padding: 20px;
background-color: #f1f3f5;
text-align: center;
}
.layer-demo-button {
padding: 12px 24px;
border: 0;
border-radius: 4px;
font-size: 15px;
}
.layer-demo p {
margin: 12px 0 0;
font-size: 13px;
}
The components layer overrides the base layer.
The button appears green because the kd-layer-demo-components layer has higher priority than the kd-layer-demo-base layer for normal declarations.
This occurs even though the selector in the base layer has greater specificity.
In a real project, the same arrangement could use external stylesheets:
@layer base, components;
@import "base.css" layer(base);
@import "components.css" layer(components);
The browser would apply the same layer priority rules to the imported declarations.
Framework Example
One practical use of layer() is importing third-party framework styles into a lower-priority layer.
For example:
@layer framework, custom;
@import "framework.css" layer(framework);
@import "custom.css" layer(custom);
The custom layer has higher priority for normal declarations than the framework layer.
Suppose the framework contains:
.button {
background-color: blue;
}
And the custom stylesheet contains:
.button {
background-color: green;
}
The button appears green because the custom stylesheet belongs to the higher-priority layer.
This approach can reduce the need for highly specific selectors when overriding third-party styles.
Be aware that rules written outside explicit layers have higher priority than normal declarations inside those layers.
When integrating an existing framework, test its important declarations, layer usage, and stylesheet dependencies before changing the import structure.
Common Uses
The layer() function is useful for organizing external CSS and managing cascade priority.
| Use | Description |
|---|---|
| Framework styles | Place third-party CSS into a controlled layer. |
| Component styles | Group imported buttons, forms, and other components. |
| Reset styles | Assign resets to a lower-priority layer. |
| Theme styles | Organize imported theme rules. |
| Nested organization | Separate related styles into sublayers. |
| Specificity management | Control priority without continually increasing selector specificity. |
| Third-party isolation | Reduce conflicts between external and custom CSS. |
For example:
@layer reset, framework, components, utilities;
@import "reset.css" layer(reset);
@import "framework.css" layer(framework);
@import "components.css" layer(components);
@import "utilities.css" layer(utilities);
This provides a predictable layer order for the imported stylesheets.
Limitations
The layer() function has several important rules and limitations.
- It is used with the
@importat-rule, not as a regular CSS property value. - It requires a valid layer name inside the parentheses.
- Only one layer name can be supplied per
layer()function. - Nested layer names use periods between identifiers.
- Layer names are case-sensitive.
- It does not change the placement restrictions of
@import. - Importing into an existing layer does not change the layer's established order.
- Normal unlayered author declarations have higher priority than normal layered author declarations.
- Important declarations reverse the normal layer priority order.
- It does not eliminate selector specificity within the same layer.
- It does not import stylesheets by itself. The surrounding
@importrule performs the import.
For example, this is valid:
@import "styles.css" layer(components);
The following is invalid because the layer name is missing:
@import "styles.css" layer();
Use the layer keyword without parentheses to create an anonymous layer:
@import "styles.css" layer;
The following is invalid because multiple layer names cannot be separated by commas:
@import "styles.css" layer(base, components);
Use one named layer per import, or use a dot-separated name for a nested layer.
Browser Support
The CSS layer() function is Baseline Widely available. It has been supported across major browser engines since March 2022.
Modern versions of Chrome, Edge, Firefox, Safari, and other major browsers support cascade layers and the layer() function with @import.
For example:
@import "components.css" layer(components);
Older browsers that do not support cascade layers may ignore imports using the layer syntax. Do not assume that they will import the stylesheet without applying a layer.
If compatibility with older browsers is required, consider providing an alternative stylesheet structure or a build process that produces compatible CSS.
For current compatibility information, visit Can I Use? and search for CSS cascade layers.
Specifications
The layer() function is defined in the CSS Cascading and Inheritance Level 5 .
The specification defines named and anonymous layers, nested layer names, layer priority, and the use of cascade layers with imported stylesheets.
Related CSS features include the @import and @layer at-rules, the supports() import condition, selector specificity, and the CSS cascade.
