HTML and CSS course Β· Module 9: Modern CSS

CSS Nesting - Native Style Nesting

14 min read
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.

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. 1. What is native CSS Nesting?

  2. 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:

Useful articles