Вложенность 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
все вместе. Всё это очень захватывающе!