HTML and CSS course Β· Module 9: Modern CSS
CSS Nesting - Native Style Nesting
In this lesson4
In plain CSS you start every rule for the inside of a card with the same selector: .card h2, .card p, .card .button. You repeat it like a scribe copying the same heading onto every scroll, and when you rename the class, you have to fix every place. For years only Sass solved this. CSS Nesting is a native CSS feature that allows nesting selectors inside other selectors, similar to preprocessors like Sass or Less, without any compilation. This significantly improves the readability and organization of code, and since 2023 it has worked in all major browsers.
CSS Nesting Basics
Simple Nesting
Let's start with a comparison. We wrote the same card styles first in the traditional way and then with nesting:
1/* Traditional CSS */
2.card {
3 padding: 1rem;
4 background: white;
5 border-radius: 8px;
6}
7
8.card h2 {
9 font-size: 1.5rem;
10 margin-bottom: 1rem;
11 color: #333;
12}
13
14.card p {
15 line-height: 1.6;
16 color: #666;
17}
18
19.card .button {
20 padding: 0.5rem 1rem;
21 background: #007bff;
22 color: white;
23 border: none;
24 border-radius: 4px;
25}
26
27/* CSS Nesting */
28.card {
29 padding: 1rem;
30 background: white;
31 border-radius: 8px;
32
33 h2 {
34 font-size: 1.5rem;
35 margin-bottom: 1rem;
36 color: #333;
37 }
38
39 p {
40 line-height: 1.6;
41 color: #666;
42 }
43
44 .button {
45 padding: 0.5rem 1rem;
46 background: #007bff;
47 color: white;
48 border: none;
49 border-radius: 4px;
50 }
51}Both versions give an identical result. The nested h2 means exactly .card h2, a heading inside the card, and has the same specificity. Only the notation changes: the name .card appears once, and everything related to the card sits in one block.
Using the & Symbol
The & symbol represents the parent selector and allows creating more complex selectors, such as states, variants and pseudo-elements:
1.button {
2 padding: 0.75rem 1.5rem;
3 background: #007bff;
4 color: white;
5 border: none;
6 border-radius: 4px;
7 cursor: pointer;
8 transition: all 0.3s ease;
9
10 /* Hover and focus states */
11 &:hover {
12 background: #0056b3;
13 transform: translateY(-1px);
14 }
15
16 &:focus {
17 outline: none;
18 box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
19 }
20
21 &:active {
22 transform: translateY(0);
23 }
24
25 /* Button variants */
26 &.secondary {
27 background: #6c757d;
28
29 &:hover {
30 background: #545b62;
31 }
32 }
33
34 &.danger {
35 background: #dc3545;
36
37 &:hover {
38 background: #c82333;
39 }
40 }
41
42 /* State modifiers */
43 &.loading {
44 position: relative;
45 color: transparent;
46
47 &::after {
48 content: '';
49 position: absolute;
50 top: 50%;
51 left: 50%;
52 width: 16px;
53 height: 16px;
54 border: 2px solid #ffffff;
55 border-top: 2px solid transparent;
56 border-radius: 50%;
57 animation: spin 1s linear infinite;
58 transform: translate(-50%, -50%);
59 }
60 }
61
62 &:disabled {
63 opacity: 0.6;
64 cursor: not-allowed;
65
66 &:hover {
67 background: #007bff;
68 transform: none;
69 }
70 }
71}
72
73@keyframes spin {
74 0% { transform: translate(-50%, -50%) rotate(0deg); }
75 100% { transform: translate(-50%, -50%) rotate(360deg); }
76}&:hover without a space is the same button in its hover state, and &.secondary is a button that also has the secondary class. Watch out for the space: & :hover would mean any descendant of the button under the cursor. There is also an important difference from Sass: in native CSS you cannot glue a class name together with &__title, that works only in a preprocessor.
Advanced Nesting Techniques
Combinators and Pseudo-selectors
You can nest everything: descendant selectors, pseudo-classes, combinators and even media queries. Here is a whole navigation with a dropdown menu in one block:
1.navigation {
2 display: flex;
3 align-items: center;
4 padding: 1rem 2rem;
5 background: #ffffff;
6 box-shadow: 0 2px 4px rgba(0,0,0,0.1);
7
8 .logo {
9 font-size: 1.5rem;
10 font-weight: bold;
11 color: #007bff;
12 text-decoration: none;
13
14 &:hover {
15 color: #0056b3;
16 }
17 }
18
19 .nav-list {
20 display: flex;
21 list-style: none;
22 margin: 0 0 0 auto;
23 padding: 0;
24 gap: 2rem;
25
26 .nav-item {
27 position: relative;
28
29 .nav-link {
30 display: block;
31 padding: 0.5rem 0;
32 color: #333;
33 text-decoration: none;
34 font-weight: 500;
35 transition: color 0.3s ease;
36
37 &:hover {
38 color: #007bff;
39 }
40
41 &.active {
42 color: #007bff;
43
44 &::after {
45 content: '';
46 position: absolute;
47 bottom: -8px;
48 left: 0;
49 right: 0;
50 height: 2px;
51 background: #007bff;
52 }
53 }
54 }
55
56 /* Dropdown menu */
57 .dropdown {
58 position: absolute;
59 top: 100%;
60 left: 0;
61 min-width: 200px;
62 background: white;
63 border-radius: 8px;
64 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
65 opacity: 0;
66 visibility: hidden;
67 transform: translateY(-10px);
68 transition: all 0.3s ease;
69 z-index: 1000;
70
71 .dropdown-item {
72 .dropdown-link {
73 display: block;
74 padding: 0.75rem 1rem;
75 color: #333;
76 text-decoration: none;
77
78 &:hover {
79 background: #f8f9fa;
80 color: #007bff;
81 }
82
83 &:first-child {
84 border-radius: 8px 8px 0 0;
85 }
86
87 &:last-child {
88 border-radius: 0 0 8px 8px;
89 }
90 }
91 }
92 }
93
94 /* Show dropdown on hover */
95 &:hover .dropdown {
96 opacity: 1;
97 visibility: visible;
98 transform: translateY(0);
99 }
100 }
101 }
102
103 /* Responsive navigation */
104 .mobile-toggle {
105 display: none;
106 flex-direction: column;
107 gap: 4px;
108 background: none;
109 border: none;
110 cursor: pointer;
111
112 .bar {
113 width: 25px;
114 height: 3px;
115 background: #333;
116 transition: all 0.3s ease;
117 }
118
119 &.active {
120 .bar:nth-child(1) {
121 transform: rotate(45deg) translate(5px, 5px);
122 }
123
124 .bar:nth-child(2) {
125 opacity: 0;
126 }
127
128 .bar:nth-child(3) {
129 transform: rotate(-45deg) translate(7px, -6px);
130 }
131 }
132 }
133
134 @media (max-width: 768px) {
135 .nav-list {
136 position: fixed;
137 top: 70px;
138 left: 0;
139 right: 0;
140 flex-direction: column;
141 background: white;
142 padding: 1rem 2rem;
143 transform: translateY(-100%);
144 transition: transform 0.3s ease;
145 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
146
147 &.active {
148 transform: translateY(0);
149 }
150
151 .nav-item {
152 .dropdown {
153 position: static;
154 opacity: 1;
155 visibility: visible;
156 transform: none;
157 box-shadow: none;
158 background: #f8f9fa;
159 margin-top: 0.5rem;
160 }
161 }
162 }
163
164 .mobile-toggle {
165 display: flex;
166 }
167 }
168}The &:hover .dropdown rule shows the menu when the cursor is over a list item. Notice the depth, though: .dropdown-link sits six levels down, so the resulting selector has the specificity of six classes and is hard to override. This is an example of what the best practices below will teach you to avoid.
Nesting with Media Queries
A media query nested inside a rule applies to that very rule. Declarations written directly inside @media go to the parent selector:
1.hero-section {
2 display: flex;
3 align-items: center;
4 min-height: 100vh;
5 padding: 2rem;
6 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
7 color: white;
8
9 .hero-content {
10 max-width: 1200px;
11 margin: 0 auto;
12 text-align: center;
13
14 .hero-title {
15 font-size: 3.5rem;
16 font-weight: 700;
17 margin-bottom: 1.5rem;
18 line-height: 1.2;
19
20 @media (max-width: 768px) {
21 font-size: 2.5rem;
22 }
23
24 @media (max-width: 480px) {
25 font-size: 2rem;
26 }
27 }
28
29 .hero-subtitle {
30 font-size: 1.5rem;
31 font-weight: 300;
32 margin-bottom: 2rem;
33 opacity: 0.9;
34
35 @media (max-width: 768px) {
36 font-size: 1.25rem;
37 }
38
39 @media (max-width: 480px) {
40 font-size: 1.1rem;
41 }
42 }
43
44 .hero-buttons {
45 display: flex;
46 gap: 1rem;
47 justify-content: center;
48 flex-wrap: wrap;
49
50 @media (max-width: 480px) {
51 flex-direction: column;
52 align-items: center;
53 }
54
55 .btn-primary {
56 padding: 1rem 2rem;
57 font-size: 1.1rem;
58 background: rgba(255, 255, 255, 0.2);
59 border: 2px solid white;
60 color: white;
61 border-radius: 50px;
62 text-decoration: none;
63 transition: all 0.3s ease;
64 backdrop-filter: blur(10px);
65
66 &:hover {
67 background: white;
68 color: #667eea;
69 transform: translateY(-2px);
70 box-shadow: 0 8px 25px rgba(0,0,0,0.2);
71 }
72
73 @media (max-width: 480px) {
74 width: 200px;
75 }
76 }
77
78 .btn-secondary {
79 padding: 1rem 2rem;
80 font-size: 1.1rem;
81 background: transparent;
82 border: 2px solid rgba(255, 255, 255, 0.5);
83 color: white;
84 border-radius: 50px;
85 text-decoration: none;
86 transition: all 0.3s ease;
87
88 &:hover {
89 border-color: white;
90 background: rgba(255, 255, 255, 0.1);
91 }
92
93 @media (max-width: 480px) {
94 width: 200px;
95 }
96 }
97 }
98 }
99
100 @media (max-width: 768px) {
101 padding: 1rem;
102 min-height: 80vh;
103 }
104}The title and subtitle shrink at 768px and 480px, and the last media query changes the spacing of the section itself. Every breakpoint stands next to the style it modifies, so you do not have to scroll to a separate @media block at the end of the file.
Nesting @container
You nest the Container Queries from the previous lesson the same way. Let's recall the order: a container with container-type and an optional name, the @container query, styles for the children, a test at different widths:
1.card-wrapper {
2 container: card / inline-size;
3}
4
5.card-title {
6 font-size: 1.25rem;
7
8 @container card (min-width: 400px) {
9 font-size: 5cqw;
10 }
11}When the card container is at least 400px wide, the title gets 5cqw, which is 5% of the container's width. The other units work analogously: cqh measures the height, and cqi and cqb the inline and block dimensions.
Practical Nesting Examples
Complex Form
In a large component, nesting shows the structure like a plan of chambers. The whole contact form, with its fields, states and buttons, fits in a single rule:
1.contact-form {
2 max-width: 600px;
3 margin: 2rem auto;
4 padding: 2rem;
5 background: white;
6 border-radius: 12px;
7 box-shadow: 0 8px 25px rgba(0,0,0,0.1);
8
9 .form-header {
10 text-align: center;
11 margin-bottom: 2rem;
12
13 h2 {
14 font-size: 2rem;
15 color: #333;
16 margin-bottom: 0.5rem;
17 }
18
19 p {
20 color: #666;
21 font-size: 1.1rem;
22 }
23 }
24
25 .form-row {
26 display: flex;
27 gap: 1rem;
28 margin-bottom: 1.5rem;
29
30 @media (max-width: 600px) {
31 flex-direction: column;
32 }
33
34 .form-group {
35 flex: 1;
36
37 &.full-width {
38 flex-basis: 100%;
39 }
40 }
41 }
42
43 .form-group {
44 margin-bottom: 1.5rem;
45
46 label {
47 display: block;
48 margin-bottom: 0.5rem;
49 font-weight: 600;
50 color: #333;
51
52 .required {
53 color: #e74c3c;
54 margin-left: 0.25rem;
55 }
56 }
57
58 input, textarea, select {
59 width: 100%;
60 padding: 0.75rem;
61 border: 2px solid #e1e5e9;
62 border-radius: 8px;
63 font-size: 1rem;
64 transition: all 0.3s ease;
65 background: #fafbfc;
66
67 &:focus {
68 outline: none;
69 border-color: #007bff;
70 background: white;
71 box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
72 }
73
74 &::placeholder {
75 color: #adb5bd;
76 }
77
78 &.error {
79 border-color: #e74c3c;
80 background: #fff5f5;
81
82 &:focus {
83 box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.1);
84 }
85 }
86
87 &.success {
88 border-color: #28a745;
89 background: #f8fff9;
90
91 &:focus {
92 box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.1);
93 }
94 }
95 }
96
97 textarea {
98 min-height: 120px;
99 resize: vertical;
100 }
101
102 select {
103 cursor: pointer;
104 background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
105 background-position: right 0.5rem center;
106 background-repeat: no-repeat;
107 background-size: 1.5em 1.5em;
108 padding-right: 2.5rem;
109 }
110
111 .error-message {
112 display: block;
113 margin-top: 0.5rem;
114 color: #e74c3c;
115 font-size: 0.875rem;
116 }
117
118 .help-text {
119 display: block;
120 margin-top: 0.5rem;
121 color: #6c757d;
122 font-size: 0.875rem;
123 }
124 }
125
126 .checkbox-group {
127 margin: 1.5rem 0;
128
129 .checkbox-item {
130 display: flex;
131 align-items: center;
132 gap: 0.75rem;
133 margin-bottom: 1rem;
134
135 input[type="checkbox"] {
136 width: auto;
137 margin: 0;
138
139 &:checked + label::before {
140 background-color: #007bff;
141 border-color: #007bff;
142 }
143 }
144
145 label {
146 margin: 0;
147 cursor: pointer;
148 user-select: none;
149
150 a {
151 color: #007bff;
152 text-decoration: none;
153
154 &:hover {
155 text-decoration: underline;
156 }
157 }
158 }
159 }
160 }
161
162 .form-actions {
163 display: flex;
164 gap: 1rem;
165 justify-content: flex-end;
166 margin-top: 2rem;
167
168 @media (max-width: 480px) {
169 flex-direction: column;
170 }
171
172 .btn {
173 padding: 0.75rem 2rem;
174 border: none;
175 border-radius: 8px;
176 font-size: 1rem;
177 font-weight: 600;
178 cursor: pointer;
179 transition: all 0.3s ease;
180 text-decoration: none;
181 display: inline-block;
182 text-align: center;
183
184 &.btn-primary {
185 background: #007bff;
186 color: white;
187
188 &:hover:not(:disabled) {
189 background: #0056b3;
190 transform: translateY(-1px);
191 }
192
193 &:disabled {
194 opacity: 0.6;
195 cursor: not-allowed;
196 }
197 }
198
199 &.btn-secondary {
200 background: #f8f9fa;
201 color: #6c757d;
202 border: 1px solid #dee2e6;
203
204 &:hover {
205 background: #e9ecef;
206 color: #495057;
207 }
208 }
209
210 @media (max-width: 480px) {
211 width: 100%;
212 }
213 }
214 }
215
216 .loading-overlay {
217 position: absolute;
218 top: 0;
219 left: 0;
220 right: 0;
221 bottom: 0;
222 background: rgba(255, 255, 255, 0.9);
223 display: flex;
224 align-items: center;
225 justify-content: center;
226 border-radius: 12px;
227
228 .spinner {
229 width: 40px;
230 height: 40px;
231 border: 4px solid #f3f3f3;
232 border-top: 4px solid #007bff;
233 border-radius: 50%;
234 animation: spin 1s linear infinite;
235 }
236 }
237}The input, textarea, select list gets shared styles, while &:focus, &::placeholder and &.error describe their states. The &:checked + label::before notation shows that after & you can use any combinator, here the adjacent sibling.
Card Component with Variants
Variants and states of a component are a natural place for &. Notice the rule in which & stands at the end of the selector:
1.card {
2 background: white;
3 border-radius: 12px;
4 overflow: hidden;
5 transition: all 0.3s ease;
6 position: relative;
7
8 /* Shadow variants */
9 &.shadow-sm {
10 box-shadow: 0 1px 3px rgba(0,0,0,0.1);
11 }
12
13 &.shadow-md {
14 box-shadow: 0 4px 6px rgba(0,0,0,0.1);
15 }
16
17 &.shadow-lg {
18 box-shadow: 0 10px 25px rgba(0,0,0,0.15);
19 }
20
21 /* Interactive variants */
22 &.hoverable {
23 cursor: pointer;
24
25 &:hover {
26 transform: translateY(-4px);
27 box-shadow: 0 12px 30px rgba(0,0,0,0.2);
28 }
29 }
30
31 &.clickable {
32 cursor: pointer;
33 user-select: none;
34
35 &:active {
36 transform: scale(0.98);
37 }
38 }
39
40 /* Card components */
41 .card-header {
42 padding: 1.5rem;
43 border-bottom: 1px solid #f0f0f0;
44
45 &.with-image {
46 padding: 0;
47 position: relative;
48
49 .header-image {
50 width: 100%;
51 height: 200px;
52 object-fit: cover;
53 }
54
55 .header-content {
56 position: absolute;
57 bottom: 0;
58 left: 0;
59 right: 0;
60 padding: 1.5rem;
61 background: linear-gradient(transparent, rgba(0,0,0,0.7));
62 color: white;
63 }
64 }
65
66 .card-title {
67 font-size: 1.5rem;
68 font-weight: 600;
69 margin: 0 0 0.5rem 0;
70 color: #333;
71
72 .card-header.with-image & {
73 color: white;
74 }
75 }
76
77 .card-subtitle {
78 font-size: 1rem;
79 color: #666;
80 margin: 0;
81
82 .card-header.with-image & {
83 color: rgba(255,255,255,0.9);
84 }
85 }
86 }
87
88 .card-body {
89 padding: 1.5rem;
90
91 .card-text {
92 line-height: 1.6;
93 color: #555;
94 margin-bottom: 1rem;
95
96 &:last-child {
97 margin-bottom: 0;
98 }
99 }
100
101 .card-meta {
102 display: flex;
103 align-items: center;
104 gap: 1rem;
105 margin-bottom: 1rem;
106 font-size: 0.9rem;
107 color: #666;
108
109 .meta-item {
110 display: flex;
111 align-items: center;
112 gap: 0.25rem;
113
114 .icon {
115 width: 16px;
116 height: 16px;
117 }
118 }
119 }
120
121 .card-tags {
122 display: flex;
123 flex-wrap: wrap;
124 gap: 0.5rem;
125 margin-bottom: 1rem;
126
127 .tag {
128 padding: 0.25rem 0.75rem;
129 background: #f8f9fa;
130 color: #495057;
131 border-radius: 20px;
132 font-size: 0.8rem;
133 font-weight: 500;
134
135 &.primary {
136 background: #e3f2fd;
137 color: #1976d2;
138 }
139
140 &.success {
141 background: #e8f5e8;
142 color: #2e7d32;
143 }
144
145 &.warning {
146 background: #fff3e0;
147 color: #f57c00;
148 }
149
150 &.danger {
151 background: #ffebee;
152 color: #d32f2f;
153 }
154 }
155 }
156 }
157
158 .card-footer {
159 padding: 1rem 1.5rem;
160 background: #f8f9fa;
161 border-top: 1px solid #f0f0f0;
162
163 .card-actions {
164 display: flex;
165 justify-content: space-between;
166 align-items: center;
167 gap: 1rem;
168
169 @media (max-width: 480px) {
170 flex-direction: column;
171 align-items: stretch;
172 }
173
174 .action-group {
175 display: flex;
176 gap: 0.5rem;
177
178 @media (max-width: 480px) {
179 justify-content: center;
180 }
181 }
182
183 .btn {
184 padding: 0.5rem 1rem;
185 border: none;
186 border-radius: 6px;
187 font-size: 0.9rem;
188 cursor: pointer;
189 text-decoration: none;
190 transition: all 0.2s ease;
191
192 &.btn-primary {
193 background: #007bff;
194 color: white;
195
196 &:hover {
197 background: #0056b3;
198 }
199 }
200
201 &.btn-outline {
202 background: transparent;
203 color: #007bff;
204 border: 1px solid #007bff;
205
206 &:hover {
207 background: #007bff;
208 color: white;
209 }
210 }
211
212 &.btn-ghost {
213 background: transparent;
214 color: #6c757d;
215
216 &:hover {
217 background: #e9ecef;
218 color: #495057;
219 }
220 }
221 }
222 }
223 }
224
225 /* Special states */
226 &.loading {
227 pointer-events: none;
228
229 &::after {
230 content: '';
231 position: absolute;
232 top: 0;
233 left: 0;
234 right: 0;
235 bottom: 0;
236 background: rgba(255,255,255,0.8);
237 display: flex;
238 align-items: center;
239 justify-content: center;
240 }
241 }
242
243 &.disabled {
244 opacity: 0.6;
245 pointer-events: none;
246 }
247}.card-header.with-image & means: this title, but only when it is inside a header with an image. So the & symbol does not have to stand at the beginning.
CSS Nesting Best Practices
1. Limit Nesting Depth
Every nesting level is another class in the selector and higher specificity. Compare a sensible depth with an exaggerated one:
1/* Good - maximum 3-4 levels */
2.header {
3 .navigation {
4 .nav-item {
5 .nav-link {
6 /* maximum level */
7 }
8 }
9 }
10}
11
12/* Bad - too deep nesting */
13.page {
14 .content {
15 .section {
16 .container {
17 .row {
18 .column {
19 .card {
20 .header {
21 /* too deep! */
22 }
23 }
24 }
25 }
26 }
27 }
28 }
29}Three or four levels are the limit. You will enforce the max-nesting-depth rule automatically in the Stylelint lesson.
2. Use Meaningful Selector Names
Short names such as .title or .img are easy to confuse with classes of other components. It is better to prefix them with the component name:
1/* Good */
2.product-card {
3 .product-image {
4 /* styles */
5 }
6
7 .product-info {
8 .product-title { /* styles */ }
9 .product-price { /* styles */ }
10 }
11}
12
13/* Bad */
14.card {
15 .img {
16 /* styles */
17 }
18
19 .info {
20 .title { /* styles */ }
21 .price { /* styles */ }
22 }
23}Names with the product- prefix tell you at once where they belong, and they do not collide with other parts of the page.
3. Group Related Styles
Keep order inside a single block: first the layout, then the parts of the component, and finally the states and animations, separated by comments:
1.modal {
2 /* Basic layout styles */
3 position: fixed;
4 top: 0;
5 left: 0;
6 width: 100%;
7 height: 100%;
8 z-index: 1000;
9
10 /* Background and overlay */
11 .modal-backdrop {
12 position: absolute;
13 top: 0;
14 left: 0;
15 width: 100%;
16 height: 100%;
17 background: rgba(0,0,0,0.5);
18 backdrop-filter: blur(4px);
19 }
20
21 /* Modal content */
22 .modal-content {
23 position: relative;
24 max-width: 500px;
25 margin: 5% auto;
26 background: white;
27 border-radius: 12px;
28 overflow: hidden;
29
30 /* Modal components */
31 .modal-header {
32 /* styles */
33 }
34
35 .modal-body {
36 /* styles */
37 }
38
39 .modal-footer {
40 /* styles */
41 }
42 }
43
44 /* States and animations */
45 &.fade-in {
46 animation: modalFadeIn 0.3s ease;
47 }
48
49 &.fade-out {
50 animation: modalFadeOut 0.3s ease;
51 }
52}CSS Nesting significantly improves the organization and readability of CSS code, enabling the creation of more intuitive and maintainable stylesheets. The key is to exercise restraint and follow best practices. My advice: in new projects without a preprocessor, use native nesting boldly, but remember the differences from Sass. In the next lesson you will meet Cascade Layers, which put whole groups of styles in order.
Remember: nesting is like descending into the chambers of a pyramid, because a floor or two down is convenient, but whoever goes too deep loses the way.
Code for this lesson: index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>The :has() selector</title>
6 <link rel="stylesheet" href="style.css">
7</head>
8<body>
9 <h1>The :has() selector - the parent reacts to its children</h1>
10 <article>
11 <h2>Pyramid of Cheops</h2>
12 <div class="img-placeholder">IMG</div>
13 <p>One of the Seven Wonders of the World.</p>
14 </article>
15 <article>
16 <h2>Sphinx</h2>
17 <p>Guardian of the pyramids, without an illustration.</p>
18 </article>
19 <article>
20 <h2>Karnak Temple</h2>
21 <div class="video-placeholder">VIDEO</div>
22 <p>The largest temple complex.</p>
23 </article>
24</body>
25</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 native CSS Nesting?
2. Which container query unit refers to the container's width?
Hands-on tasks in the game
- Vertical ordering
Arrange the correct CSS Nesting syntax:
- Click in order
Arrange the correct syntax for a nested pseudo-selector in CSS Nesting:
- Vertical ordering
Arrange the process of using Container Queries: