Одна из наших любимых функций препроцессора 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 Техническая предварительная версия 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
:
Точность и гибкость с &
Допустим, вы хотите настроить таргетинг на .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 */
}
}
Хотя этот пример выглядит немного бесполезным, безусловно, существуют сценарии, в которых возможность повторения контекста селектора полезна.
Неверные примеры вложенности
Существует несколько сценариев синтаксиса вложения, которые недопустимы и могут вас удивить, если вы использовали вложение в препроцессорах.
Вложение и конкатенация
Многие соглашения об именах классов CSS рассчитывают на вложенность, позволяющую объединять или добавлять селекторы, как если бы они были строками. Это не работает при вложении CSS, поскольку селекторы не являются строками, а являются ссылками на объекты.
.card {
&--header {
/* is not equal to ".card--header" */
}
}
Более подробное объяснение можно найти в спецификации .
Сложный пример вложения
Вложение в списки селекторов и :is()
Рассмотрим следующий вложенный блок CSS:
.one, #two {
.three {
/* some styles */
}
}
Это первый пример, который начинается со списка селекторов , а затем продолжает вложенность. Предыдущие примеры заканчивались только списком выбора. В этом примере вложения нет ничего недопустимого, но есть потенциально сложная деталь реализации вложения внутри списков селекторов, особенно тех, которые включают селектор идентификатора.
Чтобы цель вложенности работала, любой список селекторов, который не является самым внутренним вложением, будет заключен браузером в :is()
. Эта упаковка поддерживает группировку списка селекторов в любых созданных контекстах. Побочным эффектом этой группировки :is(.one, #two)
является то, что она принимает специфику наивысшего балла в селекторах внутри круглых скобок. Именно так всегда работает :is()
, но использование синтаксиса вложенности может стать сюрпризом, поскольку он не совсем тот, который был создан. Суть трюка вкратце; вложение с идентификаторами и списками селекторов может привести к созданию селекторов с очень высокой специфичностью.
Чтобы наглядно проиллюстрировать сложный пример, предыдущий блок вложения будет применен к документу следующим образом:
:is(.one, #two) .three {
/* some styles */
}
Будьте внимательны или научите свои линтеры предупреждать, что при вложении в список селекторов, использующий селектор идентификаторов, специфичность всех вложений в этом списке селекторов будет высокой.
Смешение вложенности и объявлений
Рассмотрим следующий вложенный блок 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: использовать вложение или использовать @supports
для проверки возможности анализа селектора вложенности.
Использование вложения:
html {
.has-nesting {
display: block;
}
.no-nesting {
display: none;
}
}
Использование @supports
:
@supports (selector(&)) {
/* nesting parsing available */
}
У моего коллеги Брамуса есть отличный Codepen, демонстрирующий эту стратегию.
Отладка с помощью Chrome DevTools
Текущая поддержка вложения в DevTools минимальна. В настоящее время стили представлены на панели «Стили», как и ожидалось, но отслеживание вложенности и ее полного контекста селектора пока не поддерживается. У нас есть дизайн и планы сделать это прозрачным и понятным.
В Chrome 113 планируется дополнительная поддержка вложенности CSS. Следите за обновлениями.
Будущее
Вложенность CSS доступна только в версии 1. Версия 2 представит больше синтаксического сахара и потенциально меньше правил для запоминания. Существует большая потребность в том, чтобы анализ вложенности не был ограничен и не содержал сложных моментов.
Вложенность — это большое усовершенствование языка CSS. Это имеет значение для разработки почти всех архитектурных аспектов CSS. Это большое влияние необходимо глубоко изучить и понять, прежде чем можно будет эффективно определить версию 2.
И напоследок, вот демо , в котором используются @scope
, вложение и @layer
вместе. Это все очень увлекательно!