Каскадные слои ( правило CSS @layer
) появятся в Chromium 99, Firefox 97 и Safari 15.4 Beta. Они обеспечивают более явный контроль над вашими CSS-файлами, чтобы предотвратить конфликты стилей. Это особенно полезно для больших баз кода, систем дизайна и при управлении сторонними стилями в приложениях.
Четкое размещение слоев 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/components/footer.css' layer(components); /* footer component */
Приведенный выше фрагмент кода состоит из трех слоев: base
, layouts
и components
. Файлы нормализации, темы и типографики в base
, файл post
в layouts
, а cards
и footer
в components
. При импорте файла слои создаются с помощью функции Layer. Альтернативный подход — организовать слои в верхней части файла, объявив их перед импортом:
@layer base,
theme,
layouts,
components,
utilities;
Теперь порядок, в котором вы @import
свои стили, не будет иметь значения для порядка слоев, поскольку он уже установлен в первом экземпляре имени слоя. Это еще одна вещь, о которой стоит беспокоиться меньше. Вы по-прежнему можете присваивать импортированным файлам определенные слои, но порядок уже установлен.
Слои и каскад
Давайте сделаем шаг назад и посмотрим, где используются слои по отношению к более широкому каскаду:
Порядок старшинства такой:
- Пользовательский агент обычный (самый низкий приоритет)
- Локальный пользователь @layer
- Локальный пользователь обычный
- Автор @layers
- Автор нормальный
- Автор !важно
- Автор @layer !important
- Локальный пользователь! важно
- Пользовательский агент !important** (самый высокий приоритет)
Здесь вы можете заметить, что стили @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 имеют меньший приоритет, чем авторские обычные, которые имеют меньший приоритет, чем авторские !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
, чтобы изменить цвет, но он не применяется».
Подробнее о каскадных слоях
Вы также можете просмотреть эти ресурсы, чтобы узнать больше о каскадных слоях: