CSS Nesting
Нативная вложенность CSS позволяет писать дочерние правила внутри родительских, используя символ
&для ссылки на родительский селектор — аналогично Sass/SCSS, но встроено в браузер.
Зачем нужно
Вложенность делает CSS более читаемым и организованным, группируя связанные правила. Раньше это было возможно только в препроцессорах (Sass, Less). Теперь — нативная возможность браузеров, не требующая сборки.
Где используется
- Стилизация компонентов (все стили компонента в одном блоке)
- Состояния элементов (
:hover,:focus,:active) - Медиа-запросы внутри компонента
- Псевдоэлементы (
::before,::after) - Модификаторы и варианты компонентов
Предпосылки
- Селекторы — типы селекторов
- Каскад и специфичность — как вложенность влияет на специфичность
Базовый синтаксис
Вложенные правила
.card {
padding: 20px;
border-radius: 12px;
background: white;
/* Вложенный селектор — & можно опустить перед .class, :pseudo, ::pseudo */
.title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 8px;
}
.body {
color: #666;
line-height: 1.6;
}
.footer {
margin-top: 16px;
display: flex;
justify-content: flex-end;
}
}
/* Эквивалент без вложенности: */
.card { padding: 20px; border-radius: 12px; background: white; }
.card .title { font-size: 1.25rem; font-weight: 600; margin-bottom: 8px; }
.card .body { color: #666; line-height: 1.6; }
.card .footer { margin-top: 16px; display: flex; justify-content: flex-end; }
Символ & — ссылка на родителя
.button {
background: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 6px;
cursor: pointer;
/* & = .button */
&:hover {
background: #0056b3;
}
&:active {
transform: scale(0.98);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* &.modifier = .button.modifier (на том же элементе) */
&.primary {
background: #007bff;
}
&.danger {
background: #dc3545;
}
}
& для составных селекторов
.nav {
display: flex;
gap: 8px;
/* .nav-item — & используется для объединения */
&-item {
padding: 8px 16px;
}
/* ВНИМАНИЕ: это НЕ работает как в Sass!
Результат: .nav-item (НЕ .nav .nav-item) — только если & в начале
На самом деле в CSS nesting &-item = :is(.nav)-item = невалидно!
Для BEM используйте полный класс: */
.nav-item {
padding: 8px 16px;
}
}
В отличие от Sass, нативный CSS Nesting не поддерживает конкатенацию
&-suffix. Для BEM-нотации пишите полные классы.
Вложенные медиа-запросы
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
@media (max-width: 768px) {
padding: 0 16px;
}
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
@media (max-width: 1024px) {
grid-template-columns: repeat(2, 1fr);
}
@media (max-width: 640px) {
grid-template-columns: 1fr;
gap: 16px;
}
}
Вложенные псевдоэлементы
.link {
color: #007bff;
text-decoration: none;
&::before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
margin-right: 4px;
background: url("icon.svg") center/contain no-repeat;
}
&::after {
content: " \2192"; /* стрелка → */
}
&:hover {
text-decoration: underline;
&::after {
content: " \2192\2192"; /* двойная стрелка */
}
}
}
Глубокая вложенность
.page {
.header {
display: flex;
align-items: center;
.logo {
font-size: 1.5rem;
font-weight: bold;
}
.nav {
display: flex;
gap: 16px;
a {
color: inherit;
text-decoration: none;
&:hover {
color: #007bff;
}
}
}
}
}
Не злоупотребляйте глубокой вложенностью. 3 уровня максимум — иначе код становится нечитаемым и повышается специфичность.
Сравнение с Sass
| Возможность | CSS Nesting | Sass |
|---|---|---|
| Базовая вложенность | Да | Да |
& для родителя |
Да | Да |
&-suffix (BEM) |
Нет | Да |
@media внутри |
Да | Да |
| Переменные | CSS custom properties | $variables |
| Требует сборки | Нет | Да |
| Работа в рантайме | Да | Нет (компилируется) |
Полный пример компонента
.card {
--card-padding: 20px;
--card-radius: 12px;
background: white;
border-radius: var(--card-radius);
padding: var(--card-padding);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: box-shadow 200ms ease;
&:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
.image {
width: 100%;
aspect-ratio: 16/9;
object-fit: cover;
border-radius: calc(var(--card-radius) - 4px);
margin-bottom: 12px;
}
.title {
font-size: 1.125rem;
font-weight: 600;
margin-bottom: 8px;
}
.description {
color: #666;
font-size: 0.9rem;
line-height: 1.5;
}
.actions {
display: flex;
gap: 8px;
margin-top: 16px;
}
/* Варианты */
&.featured {
border: 2px solid #ffd700;
}
&.compact {
--card-padding: 12px;
}
/* Адаптивность */
@media (max-width: 640px) {
--card-padding: 16px;
.actions {
flex-direction: column;
}
}
}
Частые ошибки
- Попытка конкатенации
&-suffix— не работает как в Sass:.block { &-element { } /* Невалидно в CSS nesting! */ } - Слишком глубокая вложенность — повышает специфичность и ухудшает читаемость
- Вложенность тегов без
&— для тегов нужно начинать с&:.card { /* Для тегов нужно & или начальный комбинатор */ & p { color: #666; } /* или */ > p { color: #666; } } - Забыли про браузерную поддержку — проверьте Can I Use для целевой аудитории
Практика
- Переписать плоский CSS компонента с вложенностью
- Добавить
:hover,:focus,:activeчерез& - Вложить медиа-запросы внутрь компонента
- Создать компонент с вариантами через
&.modifier - Ограничить вложенность до 3 уровней
Связанные темы
- Селекторы — базовые селекторы CSS
- Каскад и специфичность — специфичность вложенных селекторов
- CSS Layers (@layer) — управление приоритетом