|
1 | | -<ComingSoon /> |
| 1 | +--- |
| 2 | +title: "CSS Cascade Layers (@layer)" |
| 3 | +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." |
| 4 | +keywords: [CSS layers, '@layer', cascade control, specificity, CSS organization, component layers, framework layers, layer precedence, unlayered styles] |
| 5 | +tags: [CSS layers, '@layer', cascade control, specificity, CSS organization, component layers, framework layers, layer precedence, unlayered styles] |
| 6 | +sidebar_label: Cascade Layers |
| 7 | +--- |
| 8 | + |
| 9 | +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). |
| 10 | + |
| 11 | +**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. |
| 12 | + |
| 13 | +<AdsComponent /> |
| 14 | +<br /> |
| 15 | + |
| 16 | +## 1. The Cascade Layer Order |
| 17 | + |
| 18 | +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. |
| 19 | + |
| 20 | +**The Key Layer Precedence Rule:** |
| 21 | + |
| 22 | +* **Earlier layers have lower priority (less important).** |
| 23 | +* **Later layers have higher priority (more important).** |
| 24 | + |
| 25 | +This means a simple selector in a late-defined layer can override a highly specific selector in an early-defined layer. |
| 26 | + |
| 27 | +### Order of Author Styles (Lowest to Highest Priority) |
| 28 | + |
| 29 | +1. **Styles within the first defined `@layer`** (e.g., `reset`). |
| 30 | +2. **Styles within later defined `@layer`s** (e.g., `utilities`). |
| 31 | +3. **Unlayered Styles** (CSS not wrapped in any `@layer` block). |
| 32 | +4. **Author `!important` declarations.** |
| 33 | + |
| 34 | + |
| 35 | +## 2. Defining and Ordering Layers |
| 36 | + |
| 37 | +You must define the order of your layers using a single `@layer` statement, typically placed at the very top of your CSS file. |
| 38 | + |
| 39 | +### 2.1. Defining the Order |
| 40 | + |
| 41 | +```css |
| 42 | +/* 1. Define the layer order (Lowest to Highest Precedence) */ |
| 43 | +@layer reset, framework, base, components, utilities; |
| 44 | +``` |
| 45 | + |
| 46 | +In this setup: `reset` has the lowest priority, and `utilities` has the highest priority among the layers. |
| 47 | + |
| 48 | +<AdsComponent /> |
| 49 | +<br /> |
| 50 | + |
| 51 | +### 2.2. The Specificity vs. Layer Rule |
| 52 | + |
| 53 | +This is the most critical concept to understand: |
| 54 | + |
| 55 | +> **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. |
| 56 | + |
| 57 | +:::tip Layer Wins |
| 58 | +Consider two rules: |
| 59 | +1. `.box` (`specificity: 0,1,0`) in the `base` layer. |
| 60 | +2. `#box-id` (`specificity: 1,0,0`) in the `utilities` layer. |
| 61 | + |
| 62 | +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. |
| 63 | +::: |
| 64 | + |
| 65 | +### 2.3. Creating Layer Blocks |
| 66 | + |
| 67 | +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. |
| 68 | + |
| 69 | +```css title="styles.css" |
| 70 | +/* -- 1. Reset Layer (Lowest Priority) -- */ |
| 71 | +@layer reset { |
| 72 | + /* This universal selector style is easily overridden by any other layer. */ |
| 73 | + * { |
| 74 | + box-sizing: border-box; |
| 75 | + } |
| 76 | +} |
| 77 | + |
| 78 | +/* -- 2. Components Layer (Mid Priority) -- */ |
| 79 | +@layer components { |
| 80 | + /* Specific component style */ |
| 81 | + .card-title { |
| 82 | + color: var(--theme-color); |
| 83 | + } |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +## 3. Unlayered Styles (The Override) |
| 88 | + |
| 89 | +Styles that are **not** included in any `@layer` block are referred to as **unlayered styles**. |
| 90 | + |
| 91 | +Unlayered styles always have a higher precedence than **all** layered styles, regardless of their position in the file or the layer order. |
| 92 | + |
| 93 | +:::warning Unlayered Priority |
| 94 | +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. |
| 95 | +::: |
| 96 | + |
| 97 | +```css title="styles.css" |
| 98 | +/* This style is NOT wrapped in @layer. Specificity: 0,1,0 */ |
| 99 | +.final-override { |
| 100 | + /* This will win over ALL layered styles, even if the selector is simpler. */ |
| 101 | + background-color: green; |
| 102 | +} |
| 103 | + |
| 104 | +/* This is a layered style that loses to the unlayered style above. Specificity: 0,1,0 */ |
| 105 | +@layer utilities { |
| 106 | + .final-override { |
| 107 | + background-color: red; |
| 108 | + } |
| 109 | +} |
| 110 | +``` |
| 111 | + |
| 112 | +<AdsComponent /> |
| 113 | +<br /> |
| 114 | + |
| 115 | +## 4. Layer Organization and Naming |
| 116 | + |
| 117 | +A common layer strategy is to move from the least specific, broadest styles to the most specific, overriding styles. |
| 118 | + |
| 119 | +| Layer Name | Typical Content | Priority | Role | |
| 120 | +| :--- | :--- | :--- | :--- | |
| 121 | +| **`reset`** | CSS resets (e.g., normalize.css), global box-sizing. | Lowest | Provides a clean slate. | |
| 122 | +| **`framework`** | Third-party libraries (Tailwind base, Bootstrap). | Low | Imports external defaults. | |
| 123 | +| **`base`** | Element selectors (`h1`, `p`, `a`), custom fonts, root variables. | Mid-Low | Defines project defaults. | |
| 124 | +| **`components`** | Reusable, complex class selectors (e.g., `.modal`, `.card`). | Mid-High | Defines component structure. | |
| 125 | +| **`utilities`** | Single-purpose, overriding classes (e.g., `.u-hidden`, `.u-text-red`). | Highest | Ensures utility classes always win. | |
| 126 | + |
| 127 | +### Nested and Imported Layers |
| 128 | + |
| 129 | +Layers can be nested, and styles can be imported directly into a layer, making framework integration seamless. |
| 130 | + |
| 131 | +:::info Layer Nesting |
| 132 | +Nesting layers helps organize large component libraries (e.g., separating forms from navigation). |
| 133 | + |
| 134 | +```css title="styles.css" |
| 135 | +/* Initial layer declaration must include the top level: */ |
| 136 | +@layer framework, components; |
| 137 | + |
| 138 | +/* Importing an external file into the 'framework' layer */ |
| 139 | +@import url('bootstrap.css') layer(framework); |
| 140 | + |
| 141 | +/* Defining a nested layer within components */ |
| 142 | +@layer components.forms { |
| 143 | + /* Styles for form components */ |
| 144 | + .input-field { border-color: gray; } |
| 145 | +} |
| 146 | +``` |
| 147 | +Styles in `components.forms` have the same precedence as `components` styles. |
| 148 | +::: |
| 149 | + |
| 150 | +<AdsComponent /> |
| 151 | +<br /> |
| 152 | + |
| 153 | +## Interactive CSS Layers Demo |
| 154 | + |
| 155 | +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. |
| 156 | + |
| 157 | +<CodePenEmbed |
| 158 | + title="Interactive CSS Layers Demo" |
| 159 | + penId="zxqajqv" |
| 160 | +/> |
0 commit comments