Каскадные слои ( правило CSS @layer
) появятся в Chromium 99, Firefox 97 и Safari 15.4 Beta. Они позволяют более явно контролировать ваши файлы CSS, чтобы предотвратить конфликты стилей. Это особенно полезно для больших кодовых баз, систем дизайна и при управлении сторонними стилями в приложениях.
Четкое распределение стилей по слоям предотвращает непредвиденные переопределения стилей и способствует созданию лучшей архитектуры CSS.
Специфика CSS и каскад
Специфичность CSS — это то, как CSS решает, какие стили применять к каким элементам. Различные селекторы, которые вы можете использовать, определяют специфичность любого правила стиля. Например, элементы менее специфичны, чем классы или атрибуты, которые, в свою очередь, менее специфичны, чем идентификаторы. Это элементарная часть изучения CSS.
Люди обращаются к соглашениям об именовании CSS, таким как BEM, чтобы предотвратить непреднамеренное переопределение специфичности. Присвоив всему единое имя класса, все помещается в одну и ту же плоскость специфичности. Однако не всегда возможно поддерживать такие организованные стили, особенно при работе со сторонним кодом и системами дизайна.
Каскадные слои призваны решить эту проблему. Они вводят новый слой в каскад CSS. В многослойных стилях приоритет слоя всегда превосходит специфичность селектора .
Например, селектор .post a.link
имеет более высокую специфичность, чем .card a
. Если вы попытаетесь стилизовать ссылку внутри карточки в посте, вы обнаружите, что будет применен более специфичный селектор.
Используя @layer
, вы можете более явно указать специфичность стиля каждого и убедиться, что стили ссылки на вашу карточку переопределяют стили ссылки на запись, даже если специфичность может быть численно ниже, если весь ваш CSS находится в одной плоскости. Это происходит из-за каскадного приоритета. Многослойные стили создают новые каскадные «плоскости».

@layer
в действии

Этот пример демонстрирует мощь каскадных слоев с использованием @layer
. Показано несколько ссылок: некоторые без применения дополнительных имен классов, одна с классом .link
и одна с классом .pink
. Затем CSS добавляет три слоя: base
, typography
и utilities
следующим образом:
@layer base {
a {
font-weight: 800;
color: red; /* ignored */
}
.link {
color: blue; /* ignored */
}
}
@layer typography {
a {
color: green; /* styles *all* links */
}
}
@layer utilities {
.pink {
color: hotpink; /* styles *all* .pink's */
}
}
В конечном итоге все ссылки либо зеленые, либо розовые. Это потому, что: хотя .link
имеет более высокую специфичность на уровне селектора, чем a
, есть цветовой стиль на a
в @layer
с более высоким приоритетом. a { color: green }
переопределяет .link { color: blue }
, когда зеленое правило находится в слое после синего правила.
Приоритет слоев важнее специфичности элементов.
Организация слоев
Вы можете организовать слои непосредственно на странице, как показано выше, или разместить их в верхней части файла.
Порядок слоев устанавливается с момента первого появления имени каждого слоя в коде.
Это означает, что если вы добавите следующее в начало файла, все ссылки будут отображаться красным цветом, а ссылка с классом .link
будет отображаться синим цветом:
@layer utilities, typography, base;
Это потому, что порядок слоев теперь обратный, помещая утилиты первыми, а базу последней. Таким образом, правила стиля в base
слое всегда будут иметь более высокую специфичность, чем правила стиля в типографском слое. Они больше не будут зелеными ссылками, а будут красными или синими.

Организация импорта
Другой способ использования @layer
— с файлами импорта. Вы можете сделать это напрямую при импорте стилей, используя функцию layer()
как в следующем примере.:
/* Base */
@import '../styles/base/normalize.css' layer(base); /* normalize or rest file */
@import '../styles/base/base.css' layer(base); /* body and base styles */
@import '../styles/base/theme.css' layer(theme); /* theme variables */
@import '../styles/base/typography.css' layer(theme); /* theme typography */
@import '../styles/base/utilities.css' layer(utilities); /* base utilities */
/* Layouts */
@import '../styles/components/post.css' layer(layouts); /* post layout */
/* Components */
@import '../styles/components/cards.css' layer(components); /* imports card */
@import '../styles/compo
nents/footer.css' layer(components); /* footer component */
В приведенном выше фрагменте кода есть три слоя: base
, layouts
и components
. Файлы normalize, theme и typography в base
, файл post
в layouts
, а cards
и footer
оба в components
. При импорте файла слои создаются с помощью функции layer . Альтернативным подходом было бы организовать ваши слои в верхней части файла, объявив их перед любым импортом:
@layer base,
theme,
layouts,
components,
utilities;
Теперь порядок, в котором вы @import
свои стили, не будет иметь значения для порядка слоев, поскольку он уже установлен в первом экземпляре имени слоя. Это одна проблема, о которой стоит беспокоиться, меньше. Вы по-прежнему можете назначать импортированные файлы определенным слоям, но порядок уже установлен.

Слои и каскад
Давайте сделаем шаг назад и посмотрим, где используются слои по отношению к более широкому каскаду:
Порядок приоритета таков:
- Пользовательский агент обычный (самый низкий приоритет)
- Локальный пользователь @layer
- Локальный пользователь нормальный
- Автор @layers
- Автор нормальный
- Автор !важно
- Автор @layer !важно
- Локальный пользователь !важно
- Агент пользователя !важно** (наивысший приоритет)
Вы можете заметить, что стили @layer !important
инвертированы. Вместо того, чтобы быть менее специфичными, чем неслойные (обычные) стили, они имеют более высокий приоритет. Это связано с тем, как !important
работает в каскаде: он нарушает нормальное каскадирование в ваших таблицах стилей и меняет нормальную специфичность (приоритет) на уровне слоя.
Вложенные слои
Слои также могут быть вложены в другие слои. Следующий пример взят из объяснения каскадных слоев от Мириам Сюзанны:
@layer default {
p { max-width: 70ch; }
}
@layer framework {
@layer default {
p { margin-block: 0.75em; }
}
p { margin-bottom: 1em; }
}
В приведенном выше фрагменте кода вы можете получить доступ к framework.default
, используя .
как указатель на то, что слой default
вложен в framework
. Вы также можете записать это в более сокращенном формате:
@layer framework.default {
p { margin-block: 0.75em }
}
Полученные слои и порядок слоев следующие:
- по умолчанию
-
framework.default
-
framework
бесслоистый - бесслойный
На что следует обратить внимание
Каскадные слои могут быть великолепны, если вы используете их правильно, но они также могут создавать дополнительную путаницу и неожиданные результаты. Обратите внимание на следующее при работе с каскадными слоями:
Правило 1: Не используйте @layer
для определения области действия
Каскадные слои не решают проблему области действия. Если у вас есть файл CSS с @layer
, например card.css
, и вы хотите задать стили для всех ссылок в пределах карточки, не пишите такие стили:
a {
…
}
Это приведет к тому, что все теги a
в вашем файле получат это переопределение. Важно по-прежнему правильно определять область действия стилей:
.card a {
…
}
Правило 2: каскадные слои располагаются позади неструктурированного CSS
Важно отметить, что многослойный CSS-файл не переопределяет не многослойный CSS. Это было намеренное решение, чтобы упростить введение слоев более разумным способом для работы с существующей кодовой базой. Например, использование файла reset.css
является хорошей отправной точкой и примером использования каскадных слоев.
Правило 3: !important
инвертирует каскадную специфичность
Хотя многоуровневые стили в целом менее специфичны, чем неслойные стили, использование !important
меняет это на противоположное. В слое объявления с правилом !important
более специфичны, чем неслойные стили.
В этом случае стили !important
инвертируют свою специфичность. Диаграмма выше показывает это для справки: автор @layers имеет меньший приоритет, чем автор normal, который имеет меньший приоритет, чем автор !important, который имеет меньший приоритет, чем автор @layer !important.
Если у вас несколько слоев, первый слой с !important
будет иметь приоритет !important
и будет иметь наиболее конкретный стиль.
Правило 4: Понимание точек инъекций
Поскольку порядок слоев устанавливается при первом появлении имени каждого слоя в вашем коде, если вы поместите объявление @layer
после импорта и установки layer()
или после другого оператора @layer
, его можно проигнорировать. В отличие от CSS, где правило стиля, расположенное дальше всего на странице, применяется к каскадным слоям, порядок устанавливается в первом случае.
Это может быть в списке, в блоке слоев или в импорте. Если вы поместите @layer
после списка импорта с помощью layer()
, это ничего не даст. Размещение его в верхней части файла заставит его установить порядок слоев и поможет вам четко увидеть слои в архитектуре.
Правило №5: Следите за своей спецификой
С каскадными слоями менее конкретный селектор (например, a
) переопределит более конкретный селектор (например, .link
), если этот менее конкретный селектор находится на более конкретном слое. Рассмотрите следующее:
a
в layer(components)
переопределит .pink
в layer(utilities)
если: @layer utilities, components
было указано. Хотя это намеренная часть API, это может сбивать с толку и раздражать, если вы этого не ожидаете.
Поэтому, если вы пишете служебные классы, всегда включайте их как слой более высокого порядка, чем компоненты, которыми вы собираетесь их переопределить. Вы можете подумать: «Я только что добавил этот класс .pink
, чтобы изменить цвет, и он не применяется».
Узнайте больше о каскадных слоях
Вы также можете ознакомиться со следующими ресурсами, чтобы узнать больше о каскадных слоях: