Вложенность 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;
}
}Эти два примера функционально эквивалентны, и причина, по которой у вас есть варианты, станет яснее, когда в этой статье будут рассмотрены более сложные примеры.
Выделение кругов
Для первого примера задача состоит в том, чтобы добавить стили затухания и размытия только для кругов внутри .demo.
Без вложенности, CSS сегодня:
.demo .circle {
opacity: .25;
filter: blur(25px);
}С вложенностью, есть два допустимых способа:
/* & явно помещается перед .circle */
.demo {
& .circle {
opacity: .25;
filter: blur(25px);
}
}или
/* без &, только с отступом */
.demo {
.circle {
opacity: .25;
filter: blur(25px);
}
}В результате, все элементы с классом .circle внутри .demo размыты и почти невидимы:
Выделение треугольников и квадратов
Эта задача требует выбора нескольких вложенных элементов, также называемых групповым селектором.
Без вложенности, в CSS сегодня есть два пути:
.demo .triangle,
.demo .square {
opacity: .25;
filter: blur(25px);
}или, используя :is()
/* сгруппировано с :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);
}
}Оба варианта вложенности будут использовать :is() под капотом следующим образом.
.demo :is(.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; селекторы потомков.
Примечание. Вложенные классы без & всегда приводят к селекторам потомков. Используйте символ &, чтобы изменить этот результат.
Выбор всех фигур кроме розовых
Для этой задачи требуется функциональный псевдокласс :not(), в котором элементы не должны иметь указанный селектор.
Без вложенности 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:
Точность и гибкость с &
Скажем, вы хотели выбрать .demo с помощью селектора :not(). & потребуется для этого:
.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 карты, чтобы продемонстрировать, что дополнительные функции вложения продолжают работать.
Узнайте больше о вложении @rules.
Вложения где угодно
Все примеры до этого момента были продолжены или добавлены к предыдущему контексту. При необходимости вы можете полностью изменить контекст.
.card {
.featured & {
/* .featured .card */
}
}Символ & представляет собой ссылку на объект селектора (не строку) и может быть размещён в любом месте вложенного селектора. Его даже можно разместить несколько раз:
.card {
.featured & & & {
/* .featured .card .card .card */
}
}Хотя этот пример выглядит немного бесполезным, безусловно, есть сценарии, в которых возможность повторения контекста селектора удобна.
Недопустимые примеры вложения
Есть несколько недопустимых сценариев вложенного синтаксиса, которые могут вас удивить, если вы применяли вложенность в препроцессорах. Шпаргалку по допустимому синтаксису вложенности можно найти в разделе Понимание парсера вложенности в этой статье.
Имена тэгов вложенных элементов
В настоящее время HTML элементы требуют наличия символа & впереди или в обёртке с помощью :is().
.card {
h1 {
/* 🛑 h1 не начинается с символа & */
}
}Исправлено с таким синтаксисом:
.card {
& h1 {
/* ✅ теперь h1 начинается с символа & */
}
/* or */
:is(h1) {
/* ✅ теперь h1 обёрнут в :is() */
}
}Вложение и конкатенация
Многие соглашения об именах CSS классов рассчитывают на то, что вложенность может объединять и добавлять селекторы, как если бы они были строками. Это не работает в CSS вложенности, поскольку селекторы не являются строками, это ссылки на объекты.
.card {
&--header {
/* это не равно ".card--header" */
}
}Более подробное объяснение можно найти в спецификации
Смешивание вложенности и объявлений
Рассмотрим следующий вложенный CSS блок:
.card {
color: green;
& { color: blue; }
color: red;
}Цвет элемента .card будет blue.
Любые объявления смешанных стилей поднимаются вверх, как если бы они были созданы до того, как произошло какое-либо вложение. Подробнее можно узнать в спецификации.
Понимание парсера вложенности
Чтобы достичь наибольшего успеха с CSS вложением, авторы могут изучить примеры из спецификации или узнать, как синтаксический анализатор CSS работает с вложением. Обладая этими знаниями авторы могут уверенно вкладывать стили, не посматривая постоянно в правила.
Первый и самый простой способ представить синтаксический анализатор — определить символы, которые сигнализируют синтаксическому анализатору, что он использует вложенность стилей.
& @ : . > ~ + # [ *Эти символы должны выглядеть знакомыми. Некоторые из них являются комбинаторами, а некоторые предназначены для селекторов. Таким образом, в самом простом случае, если синтаксический анализатор находит ваши вложенные селекторы и они не начинаются с одного из этих символов, он потерпит неудачу и неправильно использует ваши стили.
Обнаружение возможности
Есть два отличных способа обнаружить вложенность CSS: использовать вложенность или использовать @support для проверки возможности синтаксического анализа селектора вложенности.
Использование вложенности:
html {
.has-nesting {
display: block;
}
.no-nesting {
display: none;
}
}Использование @support
@supports (selector(&)) {
/* Парсинг вложенности доступен */
}У моего коллега Bramus есть отличный CodePen, показывающий эту стратегию.
Отладка с помощью Chrome DevTools
Текущая поддержка вложенности в DevTools минимальна. В настоящее время вы обнаружите, что стили представлены на панели Стили
, как и ожидалось, но отслеживание вложения и его полного контекста селектора пока не поддерживается. У нас есть дизайн и планы, чтобы сделать это прозрачным и понятным.
В Chrome 113 планируется дополнительная поддержка Вложенности CSS. Следите за обновлениями.
Будущее
CSS Nesting/Вложенность есть только в версии 1. В версии 2 будет больше синтаксического сахара и, возможно, меньше правил для запоминания. Существует много требований, чтобы парсинг вложенности не был ограничен, чтобы не было списка символов, которые активируют парсер.
Вложенность — это большое улучшение языка CSS. Это имеет отношение к разработке почти каждого архитектурного аспекта CSS. Это большое влияние необходимо тщательно изучить и понять, прежде чем можно будет эффективно определить версию 2.
В качестве заключительной мысли, вот демонстрация, использующая @scoop, вложенность и @layer все вместе. Всё это очень захватывающе!
