CSS Cascade Layers (@layer) let you control style precedence without fighting specificity. Here's how to use them.
Basic Layers#
1/* Define layer order */
2@layer reset, base, components, utilities;
3
4/* Styles in later layers override earlier layers */
5@layer reset {
6 * {
7 margin: 0;
8 padding: 0;
9 box-sizing: border-box;
10 }
11}
12
13@layer base {
14 body {
15 font-family: system-ui, sans-serif;
16 line-height: 1.5;
17 }
18
19 a {
20 color: blue;
21 }
22}
23
24@layer components {
25 .btn {
26 padding: 0.5rem 1rem;
27 border-radius: 4px;
28 background: #3b82f6;
29 color: white;
30 }
31}
32
33@layer utilities {
34 .text-center {
35 text-align: center;
36 }
37
38 .mt-4 {
39 margin-top: 1rem;
40 }
41}Layer Precedence#
1/* Order declaration determines precedence */
2@layer first, second, third;
3
4/* third > second > first */
5@layer first {
6 .box {
7 background: red;
8 }
9}
10
11@layer second {
12 .box {
13 background: green; /* Wins over first */
14 }
15}
16
17@layer third {
18 .box {
19 background: blue; /* Wins over second */
20 }
21}
22
23/* Result: .box has blue background */Anonymous Layers#
1/* Unnamed layers in order of appearance */
2@layer {
3 /* Anonymous layer 1 */
4 .card {
5 padding: 1rem;
6 }
7}
8
9@layer {
10 /* Anonymous layer 2 - higher precedence */
11 .card {
12 padding: 2rem;
13 }
14}Nested Layers#
1@layer components {
2 /* Sub-layers within components */
3 @layer buttons {
4 .btn {
5 padding: 0.5rem 1rem;
6 }
7 }
8
9 @layer cards {
10 .card {
11 border-radius: 8px;
12 }
13 }
14}
15
16/* Access nested layers with dot notation */
17@layer components.buttons {
18 .btn-primary {
19 background: #3b82f6;
20 }
21}
22
23@layer components.cards {
24 .card-elevated {
25 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
26 }
27}Importing with Layers#
1/* Import entire stylesheet into layer */
2@import url('reset.css') layer(reset);
3@import url('typography.css') layer(base);
4@import url('components.css') layer(components);
5
6/* Import into nested layer */
7@import url('buttons.css') layer(components.buttons);Framework Integration#
1/* Layer third-party CSS */
2@layer reset, vendor, components, utilities;
3
4/* Import framework into vendor layer */
5@import url('bootstrap.css') layer(vendor);
6
7/* Your styles override framework */
8@layer components {
9 .btn {
10 /* Your button styles override Bootstrap */
11 border-radius: 9999px;
12 }
13}Unlayered Styles#
1@layer base, components;
2
3@layer base {
4 .text {
5 color: gray;
6 }
7}
8
9/* Unlayered styles have highest precedence */
10.text {
11 color: red; /* Wins over any layer */
12}
13
14@layer components {
15 .text {
16 color: blue; /* Still loses to unlayered */
17 }
18}Design System Layers#
1/* Define comprehensive layer structure */
2@layer
3 reset,
4 tokens,
5 base,
6 layout,
7 components,
8 patterns,
9 utilities,
10 overrides;
11
12@layer reset {
13 *,
14 *::before,
15 *::after {
16 box-sizing: border-box;
17 margin: 0;
18 padding: 0;
19 }
20}
21
22@layer tokens {
23 :root {
24 --color-primary: #3b82f6;
25 --color-secondary: #8b5cf6;
26 --spacing-4: 1rem;
27 --radius-md: 0.5rem;
28 }
29}
30
31@layer base {
32 body {
33 font-family: system-ui;
34 color: #1f2937;
35 }
36
37 h1,
38 h2,
39 h3 {
40 line-height: 1.2;
41 }
42}
43
44@layer layout {
45 .container {
46 max-width: 1200px;
47 margin: 0 auto;
48 padding: 0 var(--spacing-4);
49 }
50
51 .grid {
52 display: grid;
53 gap: var(--spacing-4);
54 }
55}
56
57@layer components {
58 .button {
59 padding: 0.5rem 1rem;
60 border-radius: var(--radius-md);
61 background: var(--color-primary);
62 }
63
64 .card {
65 padding: var(--spacing-4);
66 border-radius: var(--radius-md);
67 background: white;
68 }
69}
70
71@layer utilities {
72 .sr-only {
73 position: absolute;
74 width: 1px;
75 height: 1px;
76 overflow: hidden;
77 clip: rect(0, 0, 0, 0);
78 }
79
80 .flex {
81 display: flex;
82 }
83
84 .items-center {
85 align-items: center;
86 }
87}
88
89@layer overrides {
90 /* Last resort overrides */
91}Component Variants#
1@layer components {
2 @layer base {
3 .alert {
4 padding: 1rem;
5 border-radius: 4px;
6 border: 1px solid;
7 }
8 }
9
10 @layer variants {
11 .alert-success {
12 background: #d1fae5;
13 border-color: #10b981;
14 color: #065f46;
15 }
16
17 .alert-error {
18 background: #fee2e2;
19 border-color: #ef4444;
20 color: #991b1b;
21 }
22 }
23
24 @layer states {
25 .alert-dismissible {
26 padding-right: 3rem;
27 position: relative;
28 }
29 }
30}Media Query Layers#
1@layer base, responsive;
2
3@layer base {
4 .sidebar {
5 width: 100%;
6 }
7}
8
9@layer responsive {
10 @media (min-width: 768px) {
11 .sidebar {
12 width: 300px;
13 }
14 }
15}Specificity Within Layers#
1@layer components {
2 /* Lower specificity still wins within same layer */
3 .btn {
4 background: blue;
5 }
6
7 /* Higher specificity in same layer */
8 button.btn {
9 background: red; /* Wins due to specificity */
10 }
11}
12
13@layer utilities {
14 /* Different layer - always wins over components */
15 .bg-green {
16 background: green !important; /* Wins over everything in components */
17 }
18}Revert Layer#
1@layer base {
2 a {
3 color: blue;
4 text-decoration: none;
5 }
6}
7
8@layer components {
9 .link {
10 /* Revert to previous layer's value */
11 color: revert-layer; /* blue from base */
12 text-decoration: underline;
13 }
14
15 .link-reset {
16 /* Revert all properties */
17 all: revert-layer;
18 }
19}Print Styles#
1@layer screen, print;
2
3@layer screen {
4 .no-print {
5 display: block;
6 }
7
8 .print-only {
9 display: none;
10 }
11}
12
13@layer print {
14 @media print {
15 .no-print {
16 display: none;
17 }
18
19 .print-only {
20 display: block;
21 }
22
23 body {
24 font-size: 12pt;
25 }
26 }
27}JavaScript Layer Detection#
1// Check if cascade layers are supported
2if (CSS.supports('@layer base { }')) {
3 console.log('Cascade layers supported');
4}
5
6// Dynamically add layered styles
7const style = document.createElement('style');
8style.textContent = `
9 @layer dynamic {
10 .dynamic-content {
11 opacity: 1;
12 }
13 }
14`;
15document.head.appendChild(style);Best Practices#
Structure:
✓ Declare layer order upfront
✓ Use descriptive layer names
✓ Nest related sub-layers
✓ Keep utilities last
Third-Party:
✓ Layer external CSS
✓ Your code in higher layers
✓ Avoid !important wars
✓ Document layer structure
Architecture:
✓ reset → base → components → utilities
✓ Consistent naming convention
✓ Single responsibility layers
✓ Document layer purposes
Avoid:
✗ Too many layers
✗ Deeply nested layers
✗ Unlayered styles mixed in
✗ Ignoring specificity within layers
Conclusion#
CSS Cascade Layers provide explicit control over style precedence without specificity hacks. Define layer order upfront, use them for design systems with reset, base, components, and utilities layers. Import third-party CSS into lower-precedence layers. Remember that unlayered styles always win, and use revert-layer to fall back to previous layer values.