Skip to content

Latest commit

 

History

History
160 lines (114 loc) · 6.41 KB

File metadata and controls

160 lines (114 loc) · 6.41 KB
title CSS Cascade Layers (@layer)
description Learn how to use the @layer rule to organize CSS styles into distinct layers, gaining control over the cascade and solving specificity conflicts in complex stylesheets.
keywords
CSS layers
@layer
cascade control
specificity
CSS organization
component layers
framework layers
layer precedence
unlayered styles
tags
CSS layers
@layer
cascade control
specificity
CSS organization
component layers
framework layers
layer precedence
unlayered styles
sidebar_label Cascade Layers

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 a fixed order of precedence. Cascade Layers slot into the standard cascade but allow you to define a sub-order for your own styles.

The Key Layer Precedence Rule:

  • Earlier layers have lower priority (less important).
  • Later layers have higher priority (more important).

This means a simple selector in a late-defined layer can override a highly specific selector in an early-defined layer.

Order of Author Styles (Lowest to Highest Priority)

  1. Styles within the first defined @layer (e.g., reset).
  2. Styles within later defined @layers (e.g., utilities).
  3. Unlayered Styles (CSS not wrapped in any @layer block).
  4. Author !important declarations.

2. Defining and Ordering Layers

You must define the order of your layers using a single @layer statement, typically placed at the very 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; 

In this setup: reset has the lowest priority, and utilities has the highest priority among the layers.


2.2. The Specificity vs. Layer Rule

This is the most critical concept to understand:

Layer Order Trumps Specificity: The specificity of a selector only matters within its own layer. Once two properties conflict across two different layers, the layer order determines the winner, ignoring specificity.

:::tip Layer Wins Consider two rules:

  1. .box (specificity: 0,1,0) in the base layer.
  2. #box-id (specificity: 1,0,0) in the utilities layer.

If utilities is defined after base, the simple .box utility will override the highly specific #box-id selector, because the utilities layer has higher precedence. This is how layers flip the cascade. :::

2.3. Creating Layer Blocks

You then wrap your styles in named @layer blocks. You can define layers across multiple files or multiple blocks in the same file; the browser will stitch them together based on the initial ordering statement.

/* -- 1. Reset Layer (Lowest Priority) -- */
@layer reset {
  /* This universal selector style is easily overridden by any other layer. */
  * {
    box-sizing: border-box;
  }
}

/* -- 2. Components Layer (Mid Priority) -- */
@layer components {
  /* Specific component style */
  .card-title {
    color: var(--theme-color);
  }
}

3. Unlayered Styles (The Override)

Styles that are not included in any @layer block are referred to as unlayered styles.

Unlayered styles always have a higher precedence than all layered styles, regardless of their position in the file or the layer order.

:::warning Unlayered Priority Use unlayered styles sparingly, typically only for final, non-negotiable overrides or small third-party snippets where integrating them into a layer is impractical. Relying heavily on unlayered styles defeats the purpose of managing the cascade with layers. The goal should be to make 99% of your styles layered. :::

/* This style is NOT wrapped in @layer. Specificity: 0,1,0 */
.final-override {
  /* This will win over ALL layered styles, even if the selector is simpler. */
  background-color: green; 
}

/* This is a layered style that loses to the unlayered style above. Specificity: 0,1,0 */
@layer utilities {
  .final-override {
    background-color: red; 
  }
}

4. Layer Organization and Naming

A common layer strategy is to move from the least specific, broadest styles to the most specific, overriding styles.

Layer Name Typical Content Priority Role
reset CSS resets (e.g., normalize.css), global box-sizing. Lowest Provides a clean slate.
framework Third-party libraries (Tailwind base, Bootstrap). Low Imports external defaults.
base Element selectors (h1, p, a), custom fonts, root variables. Mid-Low Defines project defaults.
components Reusable, complex class selectors (e.g., .modal, .card). Mid-High Defines component structure.
utilities Single-purpose, overriding classes (e.g., .u-hidden, .u-text-red). Highest Ensures utility classes always win.

Nested and Imported Layers

Layers can be nested, and styles can be imported directly into a layer, making framework integration seamless.

:::info Layer Nesting Nesting layers helps organize large component libraries (e.g., separating forms from navigation).

/* Initial layer declaration must include the top level: */
@layer framework, components;

/* Importing an external file into the 'framework' layer */
@import url('bootstrap.css') layer(framework); 

/* Defining a nested layer within components */
@layer components.forms {
    /* Styles for form components */
    .input-field { border-color: gray; }
}

Styles in components.forms have the same precedence as components styles. :::


Interactive CSS Layers Demo

This example demonstrates the precedence: The utility layer is defined later than the component layer, so the utility's style always wins. The unlayered style wins over both.