HTML and CSS course Β· Module 9: Modern CSS
Cascade Layers - Controlling the CSS Cascade Order
In this lesson4
You add a component library to your project. Its buttons have a selector such as #app .btn.btn-primary, and your simple .button class loses to it on specificity. You add !important, the library's author does the same, and a war begins in which nobody knows why the button has the color it has. CSS Cascade Layers (@layer) are a CSS feature that allows you to explicitly control the cascade order of styles. They enable organizing CSS into logical layers with a defined hierarchy of importance, which significantly simplifies managing complex stylesheets.
Cascade Layers Basics
What Are Cascade Layers?
Cascade Layers allow you to define named CSS layers, where styles from higher layers in the hierarchy take precedence over styles from lower layers, regardless of selector specificity. Here are four classic layers:
1/* Layer definition and its styles */
2@layer reset {
3 * {
4 margin: 0;
5 padding: 0;
6 box-sizing: border-box;
7 }
8}
9
10@layer base {
11 body {
12 font-family: 'Inter', sans-serif;
13 line-height: 1.6;
14 color: #333;
15 }
16
17 h1, h2, h3, h4, h5, h6 {
18 margin-bottom: 0.5em;
19 font-weight: 600;
20 }
21}
22
23@layer components {
24 .button {
25 padding: 0.75rem 1.5rem;
26 border: none;
27 border-radius: 6px;
28 background: #007bff;
29 color: white;
30 cursor: pointer;
31 }
32}
33
34@layer utilities {
35 .text-center { text-align: center; }
36 .hidden { display: none; }
37 .mt-4 { margin-top: 1rem; }
38}Without a separate declaration, the order is set by the first appearance of each name, so reset lies lowest and utilities highest. The .hidden class from utilities therefore beats any rule from components, even one with higher specificity. Specificity counts only within a single layer. Remember also that ordinary styles written outside any layer beat all layers.
Declaring Layer Order
You can explicitly define the layer order at the beginning of the stylesheet, in one short statement ending with a semicolon:
1/* Layer order definition - from lowest to highest priority */
2@layer reset, base, layout, components, utilities;
3
4/* Now you can use layers in any order in the code */
5
6@layer utilities {
7 .text-red { color: red; }
8}
9
10@layer reset {
11 * { margin: 0; }
12}
13
14@layer components {
15 .card {
16 background: white;
17 border: 1px solid #ddd;
18 padding: 1rem;
19 }
20}
21
22/* The order of definitions in code doesn't matter - only the order in the @layer declaration counts */The order of the blocks in the code does not matter, what counts is the order in the @layer declaration. I recommend always starting a stylesheet with such a line, because the whole hierarchy is then visible in one place, like a plan of floors carved at the entrance to a pyramid.
Advanced Cascade Layers Techniques
1. Nested Layers
Layers can contain their own layers. We close the whole framework in one layer and, inside it, order its reset, base, layout and utilities:
1@layer framework {
2 /* Layers nested within the framework layer */
3 @layer reset {
4 *, *::before, *::after {
5 box-sizing: border-box;
6 margin: 0;
7 padding: 0;
8 }
9
10 html {
11 line-height: 1.15;
12 -webkit-text-size-adjust: 100%;
13 }
14 }
15
16 @layer base {
17 body {
18 font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
19 font-size: 1rem;
20 line-height: 1.6;
21 color: #212529;
22 background: #ffffff;
23 }
24
25 img, svg {
26 display: block;
27 max-width: 100%;
28 height: auto;
29 }
30
31 button, input, select, textarea {
32 font: inherit;
33 }
34 }
35
36 @layer layout {
37 .container {
38 width: 100%;
39 max-width: 1200px;
40 margin: 0 auto;
41 padding: 0 1rem;
42 }
43
44 .grid {
45 display: grid;
46 gap: 1rem;
47 }
48
49 .flex {
50 display: flex;
51 align-items: center;
52 gap: 1rem;
53 }
54
55 @media (min-width: 768px) {
56 .container {
57 padding: 0 2rem;
58 }
59
60 .grid {
61 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
62 gap: 2rem;
63 }
64 }
65 }
66
67 @layer components {
68 /* UI Components */
69 .btn {
70 --btn-padding: 0.75rem 1.5rem;
71 --btn-border-radius: 6px;
72 --btn-font-weight: 500;
73 --btn-transition: all 0.2s ease;
74
75 display: inline-flex;
76 align-items: center;
77 justify-content: center;
78 padding: var(--btn-padding);
79 border: 1px solid transparent;
80 border-radius: var(--btn-border-radius);
81 font-weight: var(--btn-font-weight);
82 text-decoration: none;
83 cursor: pointer;
84 transition: var(--btn-transition);
85
86 &:focus {
87 outline: 2px solid transparent;
88 box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.5);
89 }
90
91 &:disabled {
92 opacity: 0.6;
93 cursor: not-allowed;
94 }
95 }
96
97 .btn-primary {
98 background: #007bff;
99 color: white;
100 border-color: #007bff;
101
102 &:hover:not(:disabled) {
103 background: #0056b3;
104 border-color: #0056b3;
105 }
106 }
107
108 .btn-secondary {
109 background: #6c757d;
110 color: white;
111 border-color: #6c757d;
112
113 &:hover:not(:disabled) {
114 background: #545b62;
115 border-color: #545b62;
116 }
117 }
118
119 .btn-outline {
120 background: transparent;
121 color: #007bff;
122 border-color: #007bff;
123
124 &:hover:not(:disabled) {
125 background: #007bff;
126 color: white;
127 }
128 }
129
130 /* Card component */
131 .card {
132 background: white;
133 border: 1px solid #e9ecef;
134 border-radius: 12px;
135 overflow: hidden;
136 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
137 transition: all 0.3s ease;
138
139 &:hover {
140 box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
141 transform: translateY(-2px);
142 }
143 }
144
145 .card-header {
146 padding: 1.5rem;
147 border-bottom: 1px solid #e9ecef;
148 background: #f8f9fa;
149 }
150
151 .card-body {
152 padding: 1.5rem;
153 }
154
155 .card-footer {
156 padding: 1rem 1.5rem;
157 border-top: 1px solid #e9ecef;
158 background: #f8f9fa;
159 }
160
161 /* Alert component */
162 .alert {
163 --alert-padding: 1rem 1.5rem;
164 --alert-border-radius: 8px;
165 --alert-border-width: 1px;
166
167 padding: var(--alert-padding);
168 border: var(--alert-border-width) solid transparent;
169 border-radius: var(--alert-border-radius);
170 margin-bottom: 1rem;
171
172 .alert-title {
173 font-weight: 600;
174 margin-bottom: 0.5rem;
175 }
176
177 &.alert-info {
178 background: #e3f2fd;
179 border-color: #2196f3;
180 color: #0d47a1;
181 }
182
183 &.alert-success {
184 background: #e8f5e8;
185 border-color: #4caf50;
186 color: #1b5e20;
187 }
188
189 &.alert-warning {
190 background: #fff3e0;
191 border-color: #ff9800;
192 color: #e65100;
193 }
194
195 &.alert-error {
196 background: #ffebee;
197 border-color: #f44336;
198 color: #b71c1c;
199 }
200 }
201 }
202}
203
204/* External styles (higher priority than framework) */
205@layer application {
206 /* Application-specific overrides */
207 .btn-primary {
208 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
209 border: none;
210
211 &:hover:not(:disabled) {
212 background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
213 }
214 }
215
216 .card {
217 backdrop-filter: blur(10px);
218 background: rgba(255, 255, 255, 0.9);
219 }
220}
221
222/* Utilities - highest priority */
223@layer utilities {
224 /* Utility classes with the highest priority */
225 .text-left { text-align: left !important; }
226 .text-center { text-align: center !important; }
227 .text-right { text-align: right !important; }
228
229 .d-none { display: none !important; }
230 .d-block { display: block !important; }
231 .d-flex { display: flex !important; }
232 .d-grid { display: grid !important; }
233
234 .m-0 { margin: 0 !important; }
235 .m-1 { margin: 0.25rem !important; }
236 .m-2 { margin: 0.5rem !important; }
237 .m-3 { margin: 1rem !important; }
238 .m-4 { margin: 1.5rem !important; }
239 .m-5 { margin: 3rem !important; }
240
241 .p-0 { padding: 0 !important; }
242 .p-1 { padding: 0.25rem !important; }
243 .p-2 { padding: 0.5rem !important; }
244 .p-3 { padding: 1rem !important; }
245 .p-4 { padding: 1.5rem !important; }
246 .p-5 { padding: 3rem !important; }
247
248 /* Responsive utilities */
249 @media (min-width: 768px) {
250 .md\:text-left { text-align: left !important; }
251 .md\:text-center { text-align: center !important; }
252 .md\:text-right { text-align: right !important; }
253
254 .md\:d-none { display: none !important; }
255 .md\:d-block { display: block !important; }
256 .md\:d-flex { display: flex !important; }
257 }
258
259 @media (min-width: 1024px) {
260 .lg\:text-left { text-align: left !important; }
261 .lg\:text-center { text-align: center !important; }
262 .lg\:text-right { text-align: right !important; }
263
264 .lg\:d-none { display: none !important; }
265 .lg\:d-block { display: block !important; }
266 .lg\:d-flex { display: flex !important; }
267 }
268}Nested layers are ordered within their parent, and the whole framework takes a single place in the page hierarchy. From the outside you refer to an inner layer with dot notation, for example @layer framework.reset.
2. Conditional Layers
Inside a layer you can use @media, @supports and @container, as well as CSS variables for themes:
1/* Layers with media queries */
2@layer responsive {
3 @media (max-width: 767px) {
4 .mobile-only {
5 display: block;
6 }
7
8 .desktop-only {
9 display: none;
10 }
11
12 .container {
13 padding: 0 1rem;
14 }
15
16 .grid {
17 grid-template-columns: 1fr;
18 }
19 }
20
21 @media (min-width: 768px) {
22 .mobile-only {
23 display: none;
24 }
25
26 .desktop-only {
27 display: block;
28 }
29
30 .container {
31 padding: 0 2rem;
32 }
33 }
34}
35
36/* Layers with feature queries */
37@layer modern {
38 @supports (display: grid) {
39 .grid-layout {
40 display: grid;
41 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
42 gap: 1rem;
43 }
44 }
45
46 @supports not (display: grid) {
47 .grid-layout {
48 display: flex;
49 flex-wrap: wrap;
50 gap: 1rem;
51 }
52
53 .grid-layout > * {
54 flex: 1 1 250px;
55 }
56 }
57
58 @supports (container-type: inline-size) {
59 .responsive-component {
60 container-type: inline-size;
61 }
62
63 @container (min-width: 400px) {
64 .responsive-component .card {
65 display: flex;
66 align-items: center;
67 gap: 1rem;
68 }
69 }
70 }
71}
72
73/* Theme layers */
74@layer themes {
75 [data-theme="light"] {
76 --bg-primary: #ffffff;
77 --bg-secondary: #f8f9fa;
78 --text-primary: #212529;
79 --text-secondary: #6c757d;
80 --border-color: #dee2e6;
81 }
82
83 [data-theme="dark"] {
84 --bg-primary: #1a1a1a;
85 --bg-secondary: #2d2d2d;
86 --text-primary: #ffffff;
87 --text-secondary: #b0b0b0;
88 --border-color: #404040;
89 }
90
91 [data-theme="blue"] {
92 --bg-primary: #0f1419;
93 --bg-secondary: #1e2a35;
94 --text-primary: #ffffff;
95 --text-secondary: #8fa3b0;
96 --border-color: #2a3f50;
97 }
98}The condition only decides whether the rules apply. The layer's position in the hierarchy stays the same regardless of the screen width or browser support.
Practical Applications of Cascade Layers
1. CSS Architecture in Large Projects
This is what the full architecture of a large project with seven layers can look like. The block is long, so treat it as a map to browse, not a text to learn by heart:
1/* Main architecture definition */
2@layer normalize, base, layout, components, pages, themes, utilities;
3
4/* 1. Normalize/Reset */
5@layer normalize {
6 /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
7
8 html {
9 line-height: 1.15;
10 -webkit-text-size-adjust: 100%;
11 }
12
13 body {
14 margin: 0;
15 }
16
17 main {
18 display: block;
19 }
20
21 h1 {
22 font-size: 2em;
23 margin: 0.67em 0;
24 }
25
26 /* ... rest of normalize.css ... */
27}
28
29/* 2. Base styles */
30@layer base {
31 :root {
32 /* Design tokens */
33 --font-family-base: 'Inter', system-ui, sans-serif;
34 --font-family-mono: 'JetBrains Mono', 'Fira Code', monospace;
35
36 --font-size-xs: 0.75rem;
37 --font-size-sm: 0.875rem;
38 --font-size-base: 1rem;
39 --font-size-lg: 1.125rem;
40 --font-size-xl: 1.25rem;
41 --font-size-2xl: 1.5rem;
42 --font-size-3xl: 1.875rem;
43 --font-size-4xl: 2.25rem;
44
45 --color-primary: #007bff;
46 --color-secondary: #6c757d;
47 --color-success: #28a745;
48 --color-warning: #ffc107;
49 --color-danger: #dc3545;
50 --color-info: #17a2b8;
51
52 --spacing-xs: 0.25rem;
53 --spacing-sm: 0.5rem;
54 --spacing-md: 1rem;
55 --spacing-lg: 1.5rem;
56 --spacing-xl: 2rem;
57 --spacing-2xl: 2.5rem;
58 --spacing-3xl: 3rem;
59
60 --border-radius-sm: 4px;
61 --border-radius-md: 8px;
62 --border-radius-lg: 12px;
63 --border-radius-xl: 16px;
64 --border-radius-full: 50%;
65
66 --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
67 --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
68 --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.15);
69 }
70
71 body {
72 font-family: var(--font-family-base);
73 font-size: var(--font-size-base);
74 line-height: 1.6;
75 color: var(--text-primary, #212529);
76 background: var(--bg-primary, #ffffff);
77 }
78
79 h1, h2, h3, h4, h5, h6 {
80 margin-top: 0;
81 margin-bottom: var(--spacing-md);
82 font-weight: 600;
83 line-height: 1.2;
84 color: var(--text-primary, #212529);
85 }
86
87 p {
88 margin-top: 0;
89 margin-bottom: var(--spacing-md);
90 color: var(--text-secondary, #6c757d);
91 }
92
93 a {
94 color: var(--color-primary);
95 text-decoration: none;
96
97 &:hover {
98 text-decoration: underline;
99 }
100 }
101
102 img, svg {
103 display: block;
104 max-width: 100%;
105 height: auto;
106 }
107
108 code {
109 font-family: var(--font-family-mono);
110 font-size: 0.9em;
111 background: rgba(0, 0, 0, 0.1);
112 padding: 0.2em 0.4em;
113 border-radius: var(--border-radius-sm);
114 }
115}
116
117/* 3. Layout patterns */
118@layer layout {
119 .container {
120 width: 100%;
121 max-width: 1200px;
122 margin: 0 auto;
123 padding: 0 var(--spacing-md);
124 }
125
126 .container-fluid {
127 width: 100%;
128 padding: 0 var(--spacing-md);
129 }
130
131 .row {
132 display: flex;
133 flex-wrap: wrap;
134 margin: 0 calc(var(--spacing-md) * -0.5);
135 }
136
137 .col {
138 flex: 1;
139 padding: 0 calc(var(--spacing-md) * 0.5);
140 }
141
142 .grid {
143 display: grid;
144 gap: var(--spacing-md);
145 }
146
147 .grid-auto {
148 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
149 }
150
151 .flex {
152 display: flex;
153 }
154
155 .flex-column {
156 flex-direction: column;
157 }
158
159 .items-center {
160 align-items: center;
161 }
162
163 .justify-center {
164 justify-content: center;
165 }
166
167 .justify-between {
168 justify-content: space-between;
169 }
170
171 .gap-sm { gap: var(--spacing-sm); }
172 .gap-md { gap: var(--spacing-md); }
173 .gap-lg { gap: var(--spacing-lg); }
174
175 @media (min-width: 768px) {
176 .container {
177 padding: 0 var(--spacing-lg);
178 }
179
180 .grid {
181 gap: var(--spacing-lg);
182 }
183
184 .md\:flex-row {
185 flex-direction: row;
186 }
187
188 .md\:gap-xl {
189 gap: var(--spacing-xl);
190 }
191 }
192
193 @media (min-width: 1024px) {
194 .container {
195 padding: 0 var(--spacing-xl);
196 }
197
198 .lg\:grid-cols-3 {
199 grid-template-columns: repeat(3, 1fr);
200 }
201
202 .lg\:grid-cols-4 {
203 grid-template-columns: repeat(4, 1fr);
204 }
205 }
206}
207
208/* 4. Reusable components */
209@layer components {
210 /* Button system */
211 .btn {
212 --btn-padding-y: var(--spacing-sm);
213 --btn-padding-x: var(--spacing-md);
214 --btn-font-size: var(--font-size-base);
215 --btn-border-radius: var(--border-radius-md);
216
217 display: inline-flex;
218 align-items: center;
219 justify-content: center;
220 padding: var(--btn-padding-y) var(--btn-padding-x);
221 font-size: var(--btn-font-size);
222 font-weight: 500;
223 border: 1px solid transparent;
224 border-radius: var(--btn-border-radius);
225 text-decoration: none;
226 cursor: pointer;
227 transition: all 0.2s ease;
228 user-select: none;
229
230 &:focus {
231 outline: 2px solid transparent;
232 box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.5);
233 }
234
235 &:disabled {
236 opacity: 0.6;
237 cursor: not-allowed;
238 pointer-events: none;
239 }
240
241 /* Size variants */
242 &.btn-sm {
243 --btn-padding-y: var(--spacing-xs);
244 --btn-padding-x: var(--spacing-sm);
245 --btn-font-size: var(--font-size-sm);
246 }
247
248 &.btn-lg {
249 --btn-padding-y: var(--spacing-md);
250 --btn-padding-x: var(--spacing-lg);
251 --btn-font-size: var(--font-size-lg);
252 }
253
254 /* Color variants */
255 &.btn-primary {
256 background: var(--color-primary);
257 color: white;
258 border-color: var(--color-primary);
259
260 &:hover:not(:disabled) {
261 background: color-mix(in srgb, var(--color-primary) 90%, black);
262 border-color: color-mix(in srgb, var(--color-primary) 90%, black);
263 }
264 }
265
266 &.btn-secondary {
267 background: var(--color-secondary);
268 color: white;
269 border-color: var(--color-secondary);
270
271 &:hover:not(:disabled) {
272 background: color-mix(in srgb, var(--color-secondary) 90%, black);
273 border-color: color-mix(in srgb, var(--color-secondary) 90%, black);
274 }
275 }
276
277 &.btn-outline {
278 background: transparent;
279 color: var(--color-primary);
280 border-color: var(--color-primary);
281
282 &:hover:not(:disabled) {
283 background: var(--color-primary);
284 color: white;
285 }
286 }
287
288 &.btn-ghost {
289 background: transparent;
290 color: var(--color-primary);
291 border-color: transparent;
292
293 &:hover:not(:disabled) {
294 background: rgba(var(--color-primary-rgb, 0, 123, 255), 0.1);
295 }
296 }
297 }
298
299 /* Card system */
300 .card {
301 background: var(--bg-primary, white);
302 border: 1px solid var(--border-color, #e9ecef);
303 border-radius: var(--border-radius-lg);
304 overflow: hidden;
305 box-shadow: var(--shadow-sm);
306 transition: all 0.3s ease;
307
308 &.card-hover:hover {
309 box-shadow: var(--shadow-lg);
310 transform: translateY(-2px);
311 }
312
313 .card-header {
314 padding: var(--spacing-lg);
315 border-bottom: 1px solid var(--border-color, #e9ecef);
316 background: var(--bg-secondary, #f8f9fa);
317
318 .card-title {
319 margin: 0 0 var(--spacing-xs) 0;
320 font-size: var(--font-size-lg);
321 font-weight: 600;
322 color: var(--text-primary);
323 }
324
325 .card-subtitle {
326 margin: 0;
327 font-size: var(--font-size-sm);
328 color: var(--text-secondary);
329 }
330 }
331
332 .card-body {
333 padding: var(--spacing-lg);
334 }
335
336 .card-footer {
337 padding: var(--spacing-md) var(--spacing-lg);
338 border-top: 1px solid var(--border-color, #e9ecef);
339 background: var(--bg-secondary, #f8f9fa);
340 }
341 }
342
343 /* Form components */
344 .form-group {
345 margin-bottom: var(--spacing-md);
346 }
347
348 .form-label {
349 display: block;
350 margin-bottom: var(--spacing-xs);
351 font-weight: 500;
352 color: var(--text-primary);
353 }
354
355 .form-control {
356 width: 100%;
357 padding: var(--spacing-sm) var(--spacing-md);
358 font-size: var(--font-size-base);
359 border: 1px solid var(--border-color, #ced4da);
360 border-radius: var(--border-radius-md);
361 background: var(--bg-primary, white);
362 color: var(--text-primary);
363 transition: all 0.2s ease;
364
365 &:focus {
366 outline: none;
367 border-color: var(--color-primary);
368 box-shadow: 0 0 0 2px rgba(var(--color-primary-rgb, 0, 123, 255), 0.25);
369 }
370
371 &::placeholder {
372 color: var(--text-muted, #adb5bd);
373 }
374
375 &:disabled {
376 background: var(--bg-secondary, #f8f9fa);
377 opacity: 0.6;
378 cursor: not-allowed;
379 }
380 }
381
382 textarea.form-control {
383 resize: vertical;
384 min-height: 100px;
385 }
386
387 .form-text {
388 margin-top: var(--spacing-xs);
389 font-size: var(--font-size-sm);
390 color: var(--text-muted, #6c757d);
391 }
392
393 .form-error {
394 margin-top: var(--spacing-xs);
395 font-size: var(--font-size-sm);
396 color: var(--color-danger);
397 }
398}
399
400/* 5. Page-specific styles */
401@layer pages {
402 .page-home {
403 .hero {
404 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
405 color: white;
406 padding: var(--spacing-3xl) 0;
407 text-align: center;
408
409 .hero-title {
410 font-size: var(--font-size-4xl);
411 margin-bottom: var(--spacing-md);
412 }
413
414 .hero-subtitle {
415 font-size: var(--font-size-xl);
416 opacity: 0.9;
417 margin-bottom: var(--spacing-xl);
418 }
419 }
420
421 .features {
422 padding: var(--spacing-3xl) 0;
423
424 .feature-grid {
425 display: grid;
426 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
427 gap: var(--spacing-xl);
428 }
429
430 .feature-card {
431 text-align: center;
432 padding: var(--spacing-lg);
433
434 .feature-icon {
435 width: 60px;
436 height: 60px;
437 margin: 0 auto var(--spacing-md);
438 background: var(--color-primary);
439 border-radius: var(--border-radius-full);
440 display: flex;
441 align-items: center;
442 justify-content: center;
443 color: white;
444 font-size: var(--font-size-xl);
445 }
446
447 .feature-title {
448 font-size: var(--font-size-lg);
449 margin-bottom: var(--spacing-sm);
450 }
451
452 .feature-description {
453 color: var(--text-secondary);
454 }
455 }
456 }
457 }
458
459 .page-about {
460 .team-grid {
461 display: grid;
462 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
463 gap: var(--spacing-lg);
464 }
465
466 .team-member {
467 text-align: center;
468
469 .member-avatar {
470 width: 150px;
471 height: 150px;
472 border-radius: var(--border-radius-full);
473 margin: 0 auto var(--spacing-md);
474 object-fit: cover;
475 }
476
477 .member-name {
478 font-size: var(--font-size-lg);
479 margin-bottom: var(--spacing-xs);
480 }
481
482 .member-role {
483 color: var(--color-primary);
484 font-weight: 500;
485 margin-bottom: var(--spacing-sm);
486 }
487
488 .member-bio {
489 color: var(--text-secondary);
490 font-size: var(--font-size-sm);
491 }
492 }
493 }
494}
495
496/* 6. Theme overrides */
497@layer themes {
498 /* Light theme (default) */
499 :root,
500 [data-theme="light"] {
501 --bg-primary: #ffffff;
502 --bg-secondary: #f8f9fa;
503 --text-primary: #212529;
504 --text-secondary: #6c757d;
505 --text-muted: #adb5bd;
506 --border-color: #dee2e6;
507 --color-primary-rgb: 0, 123, 255;
508 }
509
510 /* Dark theme */
511 [data-theme="dark"] {
512 --bg-primary: #1a1a1a;
513 --bg-secondary: #2d2d2d;
514 --text-primary: #ffffff;
515 --text-secondary: #b0b0b0;
516 --text-muted: #6c757d;
517 --border-color: #404040;
518
519 .card {
520 background: rgba(255, 255, 255, 0.05);
521 backdrop-filter: blur(10px);
522 }
523
524 .form-control {
525 background: var(--bg-secondary);
526 border-color: var(--border-color);
527
528 &:focus {
529 background: var(--bg-primary);
530 }
531 }
532 }
533
534 /* Blue theme */
535 [data-theme="blue"] {
536 --bg-primary: #0f1419;
537 --bg-secondary: #1e2a35;
538 --text-primary: #ffffff;
539 --text-secondary: #8fa3b0;
540 --text-muted: #6c7b7f;
541 --border-color: #2a3f50;
542 --color-primary: #4fc3f7;
543 --color-primary-rgb: 79, 195, 247;
544 }
545
546 /* System preference */
547 @media (prefers-color-scheme: dark) {
548 :root:not([data-theme]) {
549 --bg-primary: #1a1a1a;
550 --bg-secondary: #2d2d2d;
551 --text-primary: #ffffff;
552 --text-secondary: #b0b0b0;
553 --text-muted: #6c757d;
554 --border-color: #404040;
555 }
556 }
557}
558
559/* 7. Utility classes - highest priority */
560@layer utilities {
561 /* Display */
562 .d-none { display: none !important; }
563 .d-block { display: block !important; }
564 .d-inline { display: inline !important; }
565 .d-inline-block { display: inline-block !important; }
566 .d-flex { display: flex !important; }
567 .d-grid { display: grid !important; }
568
569 /* Positioning */
570 .position-relative { position: relative !important; }
571 .position-absolute { position: absolute !important; }
572 .position-fixed { position: fixed !important; }
573 .position-sticky { position: sticky !important; }
574
575 /* Text alignment */
576 .text-left { text-align: left !important; }
577 .text-center { text-align: center !important; }
578 .text-right { text-align: right !important; }
579 .text-justify { text-align: justify !important; }
580
581 /* Font weights */
582 .fw-normal { font-weight: 400 !important; }
583 .fw-medium { font-weight: 500 !important; }
584 .fw-semibold { font-weight: 600 !important; }
585 .fw-bold { font-weight: 700 !important; }
586
587 /* Colors */
588 .text-primary { color: var(--color-primary) !important; }
589 .text-secondary { color: var(--text-secondary) !important; }
590 .text-muted { color: var(--text-muted) !important; }
591 .text-success { color: var(--color-success) !important; }
592 .text-warning { color: var(--color-warning) !important; }
593 .text-danger { color: var(--color-danger) !important; }
594
595 /* Background colors */
596 .bg-primary { background-color: var(--color-primary) !important; }
597 .bg-secondary { background-color: var(--bg-secondary) !important; }
598 .bg-success { background-color: var(--color-success) !important; }
599 .bg-warning { background-color: var(--color-warning) !important; }
600 .bg-danger { background-color: var(--color-danger) !important; }
601
602 /* Spacing utilities */
603 .m-0 { margin: 0 !important; }
604 .m-1 { margin: var(--spacing-xs) !important; }
605 .m-2 { margin: var(--spacing-sm) !important; }
606 .m-3 { margin: var(--spacing-md) !important; }
607 .m-4 { margin: var(--spacing-lg) !important; }
608 .m-5 { margin: var(--spacing-xl) !important; }
609
610 .p-0 { padding: 0 !important; }
611 .p-1 { padding: var(--spacing-xs) !important; }
612 .p-2 { padding: var(--spacing-sm) !important; }
613 .p-3 { padding: var(--spacing-md) !important; }
614 .p-4 { padding: var(--spacing-lg) !important; }
615 .p-5 { padding: var(--spacing-xl) !important; }
616
617 /* Margin/padding directional */
618 .mt-0 { margin-top: 0 !important; }
619 .mt-1 { margin-top: var(--spacing-xs) !important; }
620 .mt-2 { margin-top: var(--spacing-sm) !important; }
621 .mt-3 { margin-top: var(--spacing-md) !important; }
622 .mt-4 { margin-top: var(--spacing-lg) !important; }
623 .mt-5 { margin-top: var(--spacing-xl) !important; }
624
625 .mb-0 { margin-bottom: 0 !important; }
626 .mb-1 { margin-bottom: var(--spacing-xs) !important; }
627 .mb-2 { margin-bottom: var(--spacing-sm) !important; }
628 .mb-3 { margin-bottom: var(--spacing-md) !important; }
629 .mb-4 { margin-bottom: var(--spacing-lg) !important; }
630 .mb-5 { margin-bottom: var(--spacing-xl) !important; }
631
632 .pt-0 { padding-top: 0 !important; }
633 .pt-1 { padding-top: var(--spacing-xs) !important; }
634 .pt-2 { padding-top: var(--spacing-sm) !important; }
635 .pt-3 { padding-top: var(--spacing-md) !important; }
636 .pt-4 { padding-top: var(--spacing-lg) !important; }
637 .pt-5 { padding-top: var(--spacing-xl) !important; }
638
639 .pb-0 { padding-bottom: 0 !important; }
640 .pb-1 { padding-bottom: var(--spacing-xs) !important; }
641 .pb-2 { padding-bottom: var(--spacing-sm) !important; }
642 .pb-3 { padding-bottom: var(--spacing-md) !important; }
643 .pb-4 { padding-bottom: var(--spacing-lg) !important; }
644 .pb-5 { padding-bottom: var(--spacing-xl) !important; }
645
646 /* Responsive utilities */
647 @media (min-width: 768px) {
648 .md\:d-none { display: none !important; }
649 .md\:d-block { display: block !important; }
650 .md\:d-flex { display: flex !important; }
651 .md\:text-left { text-align: left !important; }
652 .md\:text-center { text-align: center !important; }
653 .md\:text-right { text-align: right !important; }
654 }
655
656 @media (min-width: 1024px) {
657 .lg\:d-none { display: none !important; }
658 .lg\:d-block { display: block !important; }
659 .lg\:d-flex { display: flex !important; }
660 .lg\:text-left { text-align: left !important; }
661 .lg\:text-center { text-align: center !important; }
662 .lg\:text-right { text-align: right !important; }
663 }
664}Each layer has one job: pages stands above the components, themes above the pages, and utilities at the very top, because a helper class should always win.
2. Integration with CSS Frameworks
Layers solve the problem from the beginning of the lesson. You put the framework's code in lower layers and your own components in higher ones:
1/* Integration with Tailwind CSS */
2@layer tailwind-base, components, tailwind-utilities;
3
4@layer tailwind-base {
5 /* Tailwind's base styles */
6 @tailwind base;
7}
8
9@layer components {
10 /* Custom components over Tailwind's base */
11 .btn-custom {
12 @apply px-4 py-2 bg-blue-500 text-white rounded-lg;
13
14 &:hover {
15 @apply bg-blue-600;
16 }
17 }
18
19 .card-custom {
20 @apply bg-white shadow-lg rounded-xl p-6;
21
22 .card-title {
23 @apply text-xl font-semibold mb-2;
24 }
25
26 .card-content {
27 @apply text-gray-600 leading-relaxed;
28 }
29 }
30}
31
32@layer tailwind-utilities {
33 /* Tailwind's utilities have highest priority */
34 @tailwind utilities;
35}
36
37/* Integration with Bootstrap */
38@layer bootstrap-reboot, bootstrap-grid, components, bootstrap-utilities;
39
40@layer bootstrap-reboot {
41 /* Bootstrap's reboot styles */
42}
43
44@layer bootstrap-grid {
45 /* Bootstrap's grid system */
46 .container {
47 width: 100%;
48 padding-right: 15px;
49 padding-left: 15px;
50 margin-right: auto;
51 margin-left: auto;
52 }
53
54 .row {
55 display: flex;
56 flex-wrap: wrap;
57 margin-right: -15px;
58 margin-left: -15px;
59 }
60
61 .col {
62 flex: 1 0 0%;
63 padding-right: 15px;
64 padding-left: 15px;
65 }
66}
67
68@layer components {
69 /* Custom components that enhance Bootstrap */
70 .btn-gradient {
71 background: linear-gradient(45deg, #007bff, #0056b3);
72 border: none;
73
74 &:hover {
75 background: linear-gradient(45deg, #0056b3, #004085);
76 }
77 }
78
79 .card-modern {
80 backdrop-filter: blur(10px);
81 background: rgba(255, 255, 255, 0.9);
82 border: 1px solid rgba(255, 255, 255, 0.2);
83 }
84}
85
86@layer bootstrap-utilities {
87 /* Bootstrap's utility classes */
88}The Tailwind example is a sketch for version 3, in which the @tailwind and @apply directives are processed by Tailwind itself. Tailwind 4 arranges its styles in the native theme, base, components and utilities layers. You can load a whole external stylesheet into a layer with @import url("bootstrap.css") layer(bootstrap).
Cascade Layers Best Practices
1. Naming and Organization Strategy
A layer's name should say what role the styles inside it play. Compare good and bad names:
1/* Good - logical layer hierarchy */
2@layer
3 reset, /* Reset/normalize styles */
4 base, /* Base typography and elements */
5 layout, /* Layout patterns and grid systems */
6 components, /* Reusable UI components */
7 pages, /* Page-specific styles */
8 themes, /* Theme variations */
9 utilities; /* Utility classes */
10
11/* Good - functional layer names */
12@layer
13 normalize,
14 design-tokens,
15 typography,
16 forms,
17 navigation,
18 content,
19 interactions,
20 responsive,
21 print;
22
23/* Bad - unclear layer names */
24@layer layer1, layer2, layer3, misc, other;Names like layer1 or misc mean nothing after a month. Choose one scheme and stick to it throughout the project.
2. Priority Management
Layers replace most uses of !important, because priority comes from the order of the layers, not from exclamation marks:
1/* Good - explicit priority management */
2@layer framework, custom, overrides;
3
4@layer framework {
5 /* CSS framework code */
6 .button {
7 padding: 0.5rem 1rem;
8 background: #007bff;
9 color: white;
10 }
11}
12
13@layer custom {
14 /* Project-specific customizations */
15 .button {
16 border-radius: 8px;
17 font-weight: 500;
18 }
19}
20
21@layer overrides {
22 /* Critical overrides */
23 .button.important {
24 background: #dc3545 !important;
25 }
26}
27
28/* Bad - relying only on !important */
29.button {
30 background: #007bff !important;
31 padding: 0.5rem 1rem !important;
32 color: white !important;
33}Watch out for a trap: !important reverses the layer order. An important declaration from the framework layer would beat an important declaration from overrides, and important declarations in layers beat important declarations outside layers. That is why you should use !important in layers only in truly exceptional cases.
3. Debugging and Development
During development you can add helper layers and even declare layers inside media queries:
1/* Layer debugging helper */
2@layer debug {
3 [data-debug="layers"] * {
4 position: relative;
5 }
6
7 [data-debug="layers"] *::before {
8 content: attr(data-layer, 'unknown');
9 position: absolute;
10 top: 0;
11 right: 0;
12 background: rgba(255, 0, 0, 0.8);
13 color: white;
14 font-size: 10px;
15 padding: 2px 4px;
16 pointer-events: none;
17 z-index: 9999;
18 }
19}
20
21/* Layers for different environments */
22@layer development {
23 /* Development-only styles */
24 .debug-grid {
25 background-image:
26 linear-gradient(rgba(255,0,0,0.1) 1px, transparent 1px),
27 linear-gradient(90deg, rgba(255,0,0,0.1) 1px, transparent 1px);
28 background-size: 20px 20px;
29 }
30
31 .debug-info {
32 position: fixed;
33 bottom: 10px;
34 right: 10px;
35 background: rgba(0, 0, 0, 0.8);
36 color: white;
37 padding: 10px;
38 font-family: monospace;
39 font-size: 12px;
40 border-radius: 4px;
41 z-index: 9999;
42 }
43}
44
45/* Conditional layer loading */
46@media (max-width: 767px) {
47 @layer mobile-specific {
48 .desktop-only {
49 display: none !important;
50 }
51
52 .mobile-nav {
53 display: block;
54 }
55 }
56}
57
58@media print {
59 @layer print {
60 * {
61 background: transparent !important;
62 color: black !important;
63 box-shadow: none !important;
64 }
65
66 .no-print {
67 display: none !important;
68 }
69 }
70}Browser developer tools show the layer name next to each rule, so you can easily check which one won.
CSS Cascade Layers fundamentally change the way CSS is managed in large projects, offering precise control over the order in which styles are applied and eliminating the need to use !important in most cases. They have worked in all major browsers since 2022. In the sandbox below, uncomment the @layer reset, base, components, utilities declaration and watch which rule wins.
Remember: layers are the floors of a pyramid, because what you see at the top depends on the floor, not on the weight of a single stone.
Code for this lesson: index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>Cascade Layers @layer</title>
6 <link rel="stylesheet" href="style.css">
7</head>
8<body>
9 <div class="container">
10 <h1>Cascade Layers</h1>
11 <button class="btn">Base button</button>
12 <button class="btn btn-primary">Primary button</button>
13 <button class="btn btn-gold">Gold button</button>
14 <p class="info">Layers control CSS priority without !important.</p>
15 </div>
16</body>
17</html>Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What is @layer used for in CSS?
Hands-on tasks in the game
- Code editor
Create cascade layers: @layer reset, base, components, utilities and see how they control cascade priority.
- Vertical ordering
Arrange @layer layers from lowest to highest priority:
- Click in order
Arrange the syntax for a Cascade Layers declaration: