Одна из наших любимых функций препроцессора CSS теперь встроена в сам язык: вложенные правила стилей.
Перед вложенностью каждый селектор необходимо было явно объявить отдельно от других. Это приводит к повторениям, большому объему таблиц стилей и неудобству в процессе редактирования.
.nesting { color: hotpink; } .nesting > .is { color: rebeccapurple; } .nesting > .is > .awesome { color: deeppink; }
После вложенности селекторы можно продолжить, а связанные с ними правила стиля можно сгруппировать внутри.
.nesting { color: hotpink; > .is { color: rebeccapurple; > .awesome { color: deeppink; } } }
Вложенность помогает разработчикам, уменьшая необходимость повторения селекторов и одновременно размещая правила стилей для связанных элементов. Она также помогает стилям соответствовать целевому HTML-коду. Если компонент .nesting из предыдущего примера был удален из проекта, можно удалить всю группу целиком, вместо того чтобы искать в файлах экземпляры связанных селекторов.
Вложенность может помочь в: - Организации - Уменьшении размера файлов - Рефакторинге
Функция вложенности доступна начиная с Chrome 112, а также её можно попробовать в Safari Technical Preview 162 .
Начало работы с вложенными CSS-стилями
В оставшейся части этой статьи для визуализации выделенных областей используется следующая демонстрационная песочница. В этом состоянии по умолчанию ничего не выделено, и все видно. Выбирая различные фигуры и размеры, вы можете попрактиковаться в использовании синтаксиса и увидеть его в действии.

Внутри песочницы находятся круги, треугольники и квадраты. Некоторые из них маленькие, средние или большие. Другие — синие, розовые или фиолетовые. Все они находятся внутри элемента, содержащего .demo . Ниже представлен предварительный просмотр HTML-элементов, на которые вы будете ориентироваться.
<div class="demo">
<div class="sm triangle pink"></div>
<div class="sm triangle blue"></div>
<div class="square blue"></div>
<div class="sm square pink"></div>
<div class="sm square blue"></div>
<div class="circle pink"></div>
…
</div>
Примеры вложенности
Вложенность CSS позволяет определять стили для элемента в контексте другого селектора.
.parent {
color: blue;
.child {
color: red;
}
}
В этом примере селектор класса .child вложен в селектор класса .parent . Это означает, что вложенный селектор .child будет применяться только к элементам, являющимся дочерними элементами элементов с классом .parent .
В качестве альтернативы этот пример можно было бы записать с использованием символа & , чтобы явно указать, где следует разместить родительский класс.
.parent {
color: blue;
& .child {
color: red;
}
}
Эти два примера функционально эквивалентны, и причина наличия вариантов станет яснее по мере рассмотрения более сложных примеров в этой статье.
Выбор кругов
В первом примере задача состоит в том, чтобы добавить стили для плавного затухания и размытия только кругов внутри демонстрации.
Без вложенности , CSS сегодня:
.demo .circle {
opacity: .25;
filter: blur(25px);
}
При использовании вложенности есть два допустимых способа:
/* & is explicitly placed in front of .circle */
.demo {
& .circle {
opacity: .25;
filter: blur(25px);
}
}
или
/* & + " " space is added for you */
.demo {
.circle {
opacity: .25;
filter: blur(25px);
}
}
В результате все элементы внутри .demo с классом .circle размываются и становятся практически невидимыми:

Выбор любых треугольников и квадратов
Для решения этой задачи требуется выбрать несколько вложенных элементов, также называемых групповыми селекторами .
Сегодня, без использования вложенных тегов , в CSS есть два способа:
.demo .triangle,
.demo .square {
opacity: .25;
filter: blur(25px);
}
или, используя :is()
/* grouped with :is() */
.demo :is(.triangle, .square) {
opacity: .25;
filter: blur(25px);
}
При использовании вложенных конструкций возможны два варианта:
.demo {
& .triangle,
& .square {
opacity: .25;
filter: blur(25px);
}
}
или
.demo {
.triangle, .square {
opacity: .25;
filter: blur(25px);
}
}
В результате внутри .demo остаются только элементы .circle :

Выбор больших треугольников и окружностей
Для решения этой задачи требуется составной селектор , в котором элементы должны содержать оба класса, чтобы быть выбранными.
Без вложенности , CSS сегодня:
.demo .lg.triangle,
.demo .lg.square {
opacity: .25;
filter: blur(25px);
}
или
.demo .lg:is(.triangle, .circle) {
opacity: .25;
filter: blur(25px);
}
При использовании вложенных конструкций возможны два варианта:
.demo {
.lg.triangle,
.lg.circle {
opacity: .25;
filter: blur(25px);
}
}
или
.demo {
.lg {
&.triangle,
&.circle {
opacity: .25;
filter: blur(25px);
}
}
}
В результате все большие треугольники и круги скрыты внутри файла .demo :

Полезный совет по использованию составных селекторов и вложенности.
Символ & здесь вам пригодится, поскольку он явно показывает, как соединять вложенные селекторы. Рассмотрим следующий пример:
.demo {
.lg {
.triangle,
.circle {
opacity: .25;
filter: blur(25px);
}
}
}
Хотя это допустимый способ вложенности, результаты не будут соответствовать ожидаемым элементам. Причина в том, что без оператора & для указания желаемого результата объединения .lg.triangle, .lg.circle фактический результат будет выглядеть так .lg .triangle, .lg .circle ; дочерние селекторы .
Выбрать все фигуры, кроме розовых.
Для решения этой задачи требуется псевдокласс, использующий функцию отрицания , элементы которого не должны иметь указанный селектор.
Без вложенности , CSS сегодня:
.demo :not(.pink) {
opacity: .25;
filter: blur(25px);
}
При использовании вложенных конструкций возможны два варианта:
.demo {
:not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
или
.demo {
& :not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
В результате все фигуры, кроме розовых, скрыты внутри файла .demo :

Точность и гибкость с помощью &
Допустим, вы хотите использовать селектор :not() для .demo . Для этого требуется оператор & :
.demo {
&:not() {
...
}
}
Это объединяет .demo и :not() в .demo:not() , в отличие от предыдущего примера, где требовалось .demo :not() . Это напоминание особенно важно, когда необходимо вложить взаимодействие :hover .
.demo {
&:hover {
/* .demo:hover */
}
:hover {
/* .demo :hover */
}
}
Больше примеров вложенности
Спецификация CSS для вложенных элементов содержит множество примеров. Если вы хотите узнать больше о синтаксисе на примерах, она охватывает широкий спектр допустимых и недопустимых примеров.
Следующие несколько примеров кратко познакомят вас с функцией вложенности CSS, чтобы помочь вам понять весь спектр возможностей, которые она предоставляет.
Вложенность @media
Поиск условий медиа-запроса, изменяющих селектор и его стили, в другом разделе таблицы стилей может сильно отвлекать. Благодаря возможности вкладывать условия непосредственно в контекст, эта проблема исчезает.
Для удобства синтаксиса, если вложенный медиа-запрос изменяет стили только для текущего контекста селектора, можно использовать минимальный синтаксис.
.card {
font-size: 1rem;
@media (width >= 1024px) {
font-size: 1.25rem;
}
}
Также можно использовать оператор & явно:
.card {
font-size: 1rem;
@media (width >= 1024px) {
&.large {
font-size: 1.25rem;
}
}
}
В этом примере показан расширенный синтаксис с использованием & , а также реализована работа с карточками .large , демонстрирующая дальнейшую работоспособность дополнительных функций вложенности.
Узнайте больше о вложенных правилах @ .
Гнездование где угодно
Все приведенные до этого момента примеры являются продолжением или дополнением к предыдущему контексту. При необходимости вы можете полностью изменить или перестроить контекст.
.card {
.featured & {
/* .featured .card */
}
}
Символ & обозначает ссылку на объект селектора (а не строку) и может быть размещен в любом месте вложенного селектора. Его можно даже использовать несколько раз:
.card {
.featured & & & {
/* .featured .card .card .card */
}
}
Хотя этот пример выглядит несколько бесполезным, безусловно, существуют ситуации, когда возможность повторного использования контекста селектора оказывается полезной.
Примеры недопустимой вложенности
Существует несколько недопустимых синтаксических конструкций с вложенной структурой, которые могут вас удивить, если вы использовали вложенную структуру в препроцессорах.
Вложенность и конкатенация
Многие соглашения об именовании CSS-классов основаны на предположении, что вложенные классы позволяют объединять или добавлять селекторы, как если бы они были строками. Вложенные классы CSS этого не делают, поскольку селекторы не являются строками, а представляют собой ссылки на объекты.
.card {
&--header {
/* is not equal to ".card--header" */
}
}
Более подробное объяснение можно найти в спецификации .
Сложный пример вложенности
Вложенность внутри списков селекторов и :is()
Рассмотрим следующий вложенный блок CSS:
.one, #two {
.three {
/* some styles */
}
}
Это первый пример, который начинается со списка селекторов , а затем продолжается вложенностью. Предыдущие примеры заканчивались только списком селекторов. В этом примере вложенности нет ничего некорректного, но есть потенциально сложная деталь реализации, касающаяся вложенности внутри списков селекторов, особенно тех, которые включают селектор ID.
Для того чтобы вложенность работала, любой список селекторов, кроме самого внутреннего, будет обернут браузером с помощью :is() . Эта обертка сохраняет группировку списка селекторов в любом созданном контексте. Побочный эффект этой группировки, :is(.one, #two) , заключается в том, что она принимает специфичность наивысшего значения среди селекторов внутри скобок. Так всегда работает `:is :is() , но это может стать неожиданностью при использовании синтаксиса вложенности, поскольку это не совсем то, что было создано изначально. Вкратце, хитрость заключается в том, что вложенность с использованием идентификаторов и списков селекторов может привести к селекторам с очень высокой специфичностью.
Чтобы наглядно показать сложный пример, предыдущий вложенный блок будет применен к документу следующим образом:
:is(.one, #two) .three {
/* some styles */
}
Внимательно следите за списком селекторов или научите линтеры предупреждать о вложенности внутри списка селекторов, использующего ID-селектор, поскольку специфичность всей вложенности внутри этого списка селекторов будет высокой.
Сочетание вложенности и объявлений
Рассмотрим следующий вложенный блок CSS:
.card {
color: green;
& { color: blue; }
color: red;
}
Цвет элементов .card будет blue .
Любые смешанные объявления стилей поднимаются наверх, как если бы они были созданы до того, как произошла какая-либо вложенность. Более подробную информацию можно найти в спецификации .
Есть способы обойти это. Следующий код оборачивает три цветовых стиля в & , что сохраняет порядок каскадирования, как, возможно, и задумывал автор. Цвет элементов .card будет красным.
.card {
color: green;
& { color: blue; }
& { color: red; }
}
На самом деле, хорошей практикой является заключение любых стилей, следующих за вложенными элементами, в символ & .
.card {
color: green;
@media (prefers-color-scheme: dark) {
color: lightgreen;
}
& {
aspect-ratio: 4/3;
}
}
Обнаружение признаков
Существует два отличных способа обнаружения вложенности CSS: использовать функцию nesting или использовать @supports для проверки возможности анализа вложенных селекторов.

Использование вложенности:
html {
.has-nesting {
display: block;
}
.no-nesting {
display: none;
}
}
Использование @supports :
@supports (selector(&)) {
/* nesting parsing available */
}
У моего коллеги Брамуса есть отличный пример на Codepen, демонстрирующий эту стратегию.
Отладка с помощью инструментов разработчика Chrome
В настоящее время поддержка вложенности в инструментах разработчика минимальна. Сейчас стили отображаются в панели «Стили», как и ожидалось, но отслеживание вложенности и полного контекста селектора пока не поддерживается. У нас есть планы по обеспечению прозрачности и ясности этого процесса.

В Chrome 113 планируется добавить поддержку вложенности CSS. Следите за обновлениями.
Будущее
Вложенность CSS пока находится только на первой версии. Во второй версии появится больше синтаксического сахара и, возможно, меньше правил для запоминания. Существует большой спрос на то, чтобы разбор вложенных элементов не был ограничен и не содержал сложных моментов.
Вложенность — это значительное улучшение языка CSS. Она оказывает влияние на разработку практически всех архитектурных аспектов CSS. Это существенное влияние необходимо глубоко изучить и понять, прежде чем можно будет эффективно специфицировать версию 2.
В заключение, вот демонстрация , в которой одновременно используются @scope , вложенность и @layer . Это очень интересно!
