CSS Cascade Layers

CSS cascade layers provide a way to organize style rules into ordered groups that participate in the cascade. Layers make it possible to control which groups of normal declarations take precedence without increasing selector specificity.

Cascade layers are created with the @layer at-rule. They are useful for separating styles such as resets, third-party CSS, base styles, components, and utilities while explicitly defining their relative priority.

Why Use Cascade Layers

Without cascade layers, developers often rely on selector specificity and source order to control which competing declarations apply. As a stylesheet grows, this can lead to increasingly specific selectors that become difficult to override.

Cascade layers provide another level of organization within the cascade.

@layer reset, base, components, utilities;

This statement establishes an explicit order for four layers. For normal declarations, rules in later layers have priority over rules in earlier layers.

The layer order can therefore express the intended relationship between groups of styles without requiring selectors to become more specific.

The @layer Rule

The @layer at-rule creates or identifies a cascade layer. A named layer can contain a block of style rules.

@layer base {
  body {
    color: #333;
    background-color: #fff;
  }
}

Additional layers can contain other groups of styles.

@layer components {
  .button {
    color: #fff;
    background-color: #0088cc;
  }
}

Named layers can be referenced again later in the stylesheet, allowing related rules to be added to the same layer.

Defining Layer Order

The order of named layers can be declared before their style rules.

@layer reset, base, components, utilities;

This creates the layers and establishes their order. For normal author declarations, the priority increases from left to right:

reset
base
components
utilities

The order is established when a layer first appears. Declaring the order near the beginning of a stylesheet makes the intended cascade easier to identify.

The layer blocks can then appear elsewhere in the stylesheet.

@layer base {
  p {
    color: #333;
  }
}
@layer utilities {
  .text-primary {
    color: #0088cc;
  }
}

Layer Precedence

For normal declarations within the same origin, declarations in a later layer take precedence over declarations in an earlier layer before selector specificity is compared between those layers.

@layer base, components;

@layer base {
  .message {
    color: #333;
  }
}
@layer components {
  .message {
    color: #0088cc;
  }
}

The normal declaration in the components layer takes precedence because that layer appears later in the established layer order.

This allows broad stylesheet architecture to control precedence instead of depending entirely on selector strength or the physical location of individual declarations.

Layers and Specificity

Cascade layer precedence is considered before selector specificity for declarations in different layers of the same origin.

@layer base, utilities;

@layer base {
  #notice .message {
    color: #333;
  }
}
@layer utilities {
  .message {
    color: #0088cc;
  }
}

For normal declarations, the rule in the later utilities layer can take precedence even though its selector has lower specificity.

Specificity still matters when competing declarations are in the same layer.

@layer components {
  .card p {
    color: #333;
  }
  .card .featured {
    color: #0088cc;
  }
}

Because both declarations are in the same layer, the normal cascade continues to compare their selectors and other cascade criteria.

Unlayered Styles

Author styles do not have to belong to a layer. Normal declarations written outside all layers take precedence over normal declarations inside author layers.

@layer components {
  .button {
    background-color: #0088cc;
  }
}
.button {
  background-color: #02bf57;
}

The unlayered normal declaration takes precedence over the normal declaration inside the components layer.

This behavior is important when introducing cascade layers into an existing stylesheet. Leaving some rules unlayered can give them greater precedence than the layered normal rules.

Nested Layers

Cascade layers can contain nested layers, allowing a larger layer to be divided into smaller ordered groups.

@layer components {
  @layer forms {
    input {
      border: 1px solid #ccc;
    }
  }
  @layer buttons {
    button {
      background-color: #0088cc;
    }
  }
}

The nested layers belong to the parent components layer and have their own ordering within that parent.

Nested layers can be useful for large stylesheets, but unnecessary layer hierarchies can make the cascade harder to follow.

Importing Styles into Layers

The @import rule can place an imported stylesheet into a cascade layer.

@import url("framework.css") layer(framework);

This can be useful for third-party styles because the imported rules can be placed in a lower-priority layer and overridden by later author layers without increasing selector specificity.

@layer framework, base, components;

@import url("framework.css") layer(framework);

As with other @import rules, imports must appear before ordinary style rules, apart from statements that CSS allows before them.

Layers and !important

Important declarations use the layer order differently from normal declarations. Among important declarations in the same origin, the layer precedence is reversed.

@layer base, utilities;

@layer base {
  .message {
    color: #333 !important;
  }
}
@layer utilities {
  .message {
    color: #0088cc !important;
  }
}

In this example, the important declaration in the earlier base layer has priority over the important declaration in the later utilities layer.

The reversed order helps protect important declarations established in earlier layers from being casually overridden by later layers.

Unlayered important declarations have lower priority than important declarations inside layers of the same origin.

Organizing a Stylesheet

A project can use layers to establish a predictable stylesheet structure.

@layer reset, base, components, utilities;

@layer reset {
  /* Reset styles */
}
@layer base {
  /* Document defaults */
}
@layer components {
  /* Buttons, cards, forms */
}
@layer utilities {
  /* Small utility classes */
}

The exact layer names and order depend on the project. The important idea is to define a clear relationship between groups of styles before individual selector conflicts occur.

Not every stylesheet needs many layers. A small project may need only a few, while a larger project can use layers to separate third-party CSS, site defaults, components, and overrides.

Cascade Layer Practices

Practice Purpose
Declare layer order early Makes the intended precedence between named layers clear.
Use descriptive layer names Shows the role of each group of styles.
Group related styles Keeps rules with similar responsibilities in the same layer.
Keep specificity reasonable Uses layer order instead of unnecessarily stronger selectors.
Account for unlayered styles Prevents unexpected precedence when layered and unlayered rules are mixed.
Use !important carefully Avoids unnecessary complexity from the reversed important layer order.

CSS Cascade Layers Example

The following example creates a base layer followed by a higher-priority components layer. Both rules use the same selector, making the effect of layer order easy to see.

@layer base, components;

@layer components {
  .message {
    color: #fff;
    background-color: #0088cc;
  }
}
@layer base {
  .message {
    color: #333;
    background-color: #eee;
  }
}

Even though the base block appears later in the stylesheet, the normal declarations in components take precedence because the layer order was established as base, components.

Open the example in the editor and change the first line to @layer components, base;. Run the example again to see how changing the layer order changes which styles take precedence.

Play in Editor