Вложенность (nesting) в CSS
Переменные дали имена вашим значениям. calc и компания их вычислили. Nesting упорядочивает селекторы, которые этими значениями пользуются: держите заголовок, кнопку и hover-стили карточки внутри .card, а не повторяйте имя родителя по всему файлу.
Вложите дочерний селектор
Пишите правило внутри другого. Вложенный селектор класса или типа присоединяется как потомок родителя (комбинатор-пробел), если вы не скажете иначе через &:
.card {
padding: 1.25rem;
border-radius: 0.75rem;
background: var(--surface, #fff);
.title {
margin: 0 0 0.5rem;
font-size: 1.25rem;
}
.body {
color: var(--muted, #444);
line-height: 1.5;
}
}
Браузер разворачивает это в .card .title и .card .body. Вы по-прежнему получаете обычные селекторы потомков — nesting это сахар для структуры и локальности, а не новая модель сопоставления.
Родительский селектор &
Используйте &, когда вложенное правило должно цепляться к тому же элементу, что и родитель — псевдоклассы, псевдоэлементы или дополнительный класс на родителе:
.button {
display: inline-flex;
padding: 0.6rem 1.1rem;
border: 0;
border-radius: 0.5rem;
background: var(--brand, #2563eb);
color: #fff;
&:hover {
background: var(--brand-hover, #1d4ed8);
}
&:focus-visible {
outline: 2px solid var(--brand, #2563eb);
outline-offset: 2px;
}
&.is-primary {
background: var(--brand-strong, #1e40af);
}
}
&:hover значит .button:hover. &.is-primary значит .button.is-primary. Без & голое :hover { } — недопустимый nesting в нативном CSS: & делает привязку явной.
Комбинаторы с &
Ставьте комбинатор после &, когда нужен прямой потомок, сосед или другая явная связь — не просто пробел потомка:
.nav {
display: flex;
gap: 0.75rem;
& > .item {
padding: 0.35rem 0.6rem;
}
& > .item + .item {
border-inline-start: 1px solid #ddd;
}
/* same as nesting .item without & — descendant */
.badge {
font-size: 0.75rem;
}
}
& > .item → .nav > .item. Вложенный .badge без & → .nav .badge. Выбирайте намеренно: случайные глубокие потомки — типичный запах nesting.
Вложите @media рядом с компонентом
Можно вкладывать at-rules вроде @media внутрь style-правила, чтобы брейкпоинты жили рядом с компонентом, который они меняют:
.hero {
padding: 2rem 1.25rem;
h1 {
font-size: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
}
@media (min-width: 48rem) {
padding: 3rem 2rem;
h1 {
max-width: 20ch;
}
}
}
После развёртывания media query по-прежнему оборачивает объявления для .hero (и .hero h1). Свяжите это с токенами и clamp() из прошлых уроков Modern Toolkit — nesting только переносит правила.
Паттерны nesting одним взглядом
📊 Шпаргалка нативного nesting
| Вы пишете | Это значит | Когда использовать |
|---|---|---|
.card { .title { } } |
.card .title |
Стилизовать потомка под компонентом |
.btn { &:hover { } } |
.btn:hover |
Псевдокласс на том же элементе |
.btn { &.big { } } |
.btn.big |
Дополнительный класс на том же элементе |
.nav { & > a { } } |
.nav > a |
Явный комбинатор прямого потомка |
.box { @media (…) { } } |
Media query, ограниченный селекторами этого правила | Держать брейкпоинты с компонентом |
Держите вложенность мелкой
Два-три уровня обычно остаются читаемыми. Более глубокие деревья возвращают проблему «пирамиды селекторов» из мира Sass: тяжёлые diff’ы, выше specificity и стили, которые имеют смысл только внутри одного гигантского родителя. Предпочитайте ясный корень компонента (.card, .nav) и вкладывайте состояния и близких детей — не всю страницу.
Связка компонента: tokens + nest + состояния
Реалистичный фрагмент связывает последние три идеи toolkit, не повторяя уроки calc или переменных:
.panel {
--panel-pad: 1rem;
padding: var(--panel-pad);
border: 1px solid #e5e7eb;
border-radius: 0.75rem;
.heading {
margin: 0 0 0.5rem;
font-weight: 600;
}
.actions {
display: flex;
gap: calc(var(--panel-pad) / 2);
margin-block-start: var(--panel-pad);
}
&.is-compact {
--panel-pad: 0.5rem;
}
@media (max-width: 36rem) {
.actions {
flex-direction: column;
}
}
}
Токены по-прежнему custom properties; calc по-прежнему выводит отступ; nesting держит heading, actions, компактное состояние и правку для маленького экрана в одном месте.
Попробуйте сами
- Возьмите плоские правила
.card {},.card .title {},.card .meta {}и перепишите их с nesting под.card. - Добавьте
&:hoverна.link, чтобы цвет менялся только у ссылки (не у вложенного span). - Вложите
@media (min-width: 40rem)внутрь.sidebar, чтобы расширить padding — в DevTools проверьте развёрнутые селекторы. - Превратите ошибочно вложенный
:hover { }(без&) в&:hover { }и убедитесь, что он валиден. - Ограничьте беспорядочный трёхуровневый nest двумя уровнями, вынеся внутренний блок в свой класс.
Частые ошибки
- Писать
:hover { }вложенно без&— неверно или не то, что вы имели в виду; используйте&:hover - Ожидать, что голое
.childзначит.parent.child— для этого нужен&.child - Слепо копировать Sass-хаки
&__elementдля BEM — нативный nesting следует грамматике селекторов CSS - Вкладывать пять уровней «потому что можно» — страдают читаемость и specificity
- Думать, что nesting заменяет
var()илиcalc()— он только группирует селекторы и at-rules
Итог
- Вкладывайте дочерние селекторы, чтобы стили компонента оставались локальными; по умолчанию они разворачиваются в потомков
- Используйте
&для состояний того же элемента (:hover,.is-active) и явных комбинаторов - Вкладывайте
@mediaрядом с компонентом, который настраиваете - Держите nest мелким; nesting — это структура, не токены и не математика
- Дальше в Modern Toolkit: container queries — стили от размера родителя, а не только viewport
🧠 Проверьте Свои Знания
Проверьте Свои Знания
Бросьте себе вызов с помощью этой интерактивной викторины и узнайте, насколько хорошо вы понимаете тему
📝 Инструкции
- Внимательно прочитайте каждый вопрос
- Выберите лучший ответ на каждый вопрос
- Вы можете пересдавать тест столько раз, сколько захотите
- Ваш прогресс будет показан вверху