Каскадные слои
Каскадные слои задают порядок, в котором стили Framework и проекта перекрывают друг друга. Они делают исход спора двух правил предсказуемым: что сильнее чего, известно заранее и не зависит от длины селектора.
Как устроены слои
Стили и токены Framework объявлены в именованных каскадных слоях
(@layer); вне слоёв остаются только @font-face и базовые единицы размерной
шкалы (Где объявлены токены). Порядок слоёв задан один раз, первым правилом core.css:
@layer sf.reset, sf.tokens, sf.base, sf.utilities, sf.components, sf.overrides, sf.states;
Главное правило каскадных слоёв: слой, объявленный позже, сильнее объявленного раньше — независимо от специфичности селектора. Специфичность решает спор только внутри одного слоя.
Без слоёв исход спора между утилитой и компонентом зависел бы от длины селектора и порядка файлов. Со слоями приоритет записан явно, один раз и для всех.
Что в каком слое
| Слой | Что в нём |
|---|---|
sf.reset |
Зарезервирован под нормализацию браузерных стилей; пуст |
sf.tokens |
Служебные переменные области просмотра |
sf.base |
Примитивы и роли (цвет, размер, прозрачность, тени), базовые стили элементов (body, input, mark), иконка |
sf.utilities |
Все классы утилит |
sf.components |
Стили компонентов |
sf.overrides |
Компонент, перенастраивающий другой компонент внутри себя |
sf.states |
Значения, зависящие от состояния, — они побеждают перенастройку |
Обратите внимание: токены цвета объявлены в sf.base, а не в sf.tokens.
Базовый стиль body в sf.base красит страницу: фон --sf-surface-0, цвет
текста --sf-on-surface. Поэтому странице своя заливка не нужна; свой фон и
цвет текста нужны только участку с другой темой
(Участок другой темы).
Три следствия порядка слоёв
Компонент сильнее утилиты. sf.components стоит после sf.utilities,
поэтому класс утилиты не перебивает собственное правило компонента. Чтобы
изменить цвет или геометрию компонентов, меняйте общие токены — роли цвета,
примитивы палитры, радиусы (см. Как менять дизайн). Утилита или более специфичный селектор
здесь не помогут.
Есть два исключения. Первое — модификаторы, которые компонент объявляет сам
под именем утилиты. Например, у кнопки .sf-button.radius-square,
.sf-button.radius-rounded и .sf-button.radius-default записаны в стилях
кнопки, в слое sf.components, и поэтому работают
(Кнопки). Такие классы перечислены на
странице компонента; остальные утилиты правило компонента не перебивают.
Второе исключение — объявления с !important: для них порядок слоёв
переворачивается. Во Framework так написана лишь малая группа утилит, которой
иначе нечем перекрасить тень в состоянии. В своём коде !important в утилите не
нужен.
CSS без слоя сильнее любого слоя. Правило проекта, написанное без
@layer, побеждает весь Framework, включая sf.states. Это удобно, но
правило Framework, оказавшееся вне слоя, становится неотключаемым. Поэтому
контракт проверяет, что цвет иконки объявлен внутри sf.base.
Порядок задаётся один раз. Повторное @layer sf.components { … } ниже по
файлу ничего не переставляет — оно дописывает правила в слой, уже занявший своё
место.
Как переопределять правильно
Свои значения общих токенов проект пишет в собственном каскадном слое,
объявленном в CSS проекта после core.css. Такой слой стоит после всех слоёв
Framework и поэтому сильнее объявлений в sf.base при любой специфичности.
Пример меняет скругление всех контролов и областей:
@layer project {
:root {
--sf-radius--ui: var(--sf-radius-1\/3);
--sf-radius--surface: var(--sf-radius-1\/2);
}
}
Правила:
- переопределяйте общие токены (роли, примитивы, ступени шкал), а не правила и переменные отдельных компонентов (см. Как менять дизайн);
- слой проекта объявляйте в CSS, подключённом после
core.css: слой, впервые названный раньше, встанет в порядке перед слоями Framework и проиграет им; - переопределение роли или примитива в CSS проекта без слоя тоже сильнее
объявления Framework в
sf.base, поэтому тему проекта не нужно усиливать специфичностью — достаточно объявить значение (см. Своя тема проекта); - слои
sf.*принадлежат Framework; правила проекта в них не пишите.
Компоненты пакета (например, пакета larena) отдельного слоя не заводят: их
стили лежат в тех же слоях Framework — sf.components, а при необходимости
sf.overrides и sf.states. Поэтому для порядка слоёв компонент пакета не
отличается от компонента Framework, и слой проекта сильнее обоих.
Как узнать, какое правило победило
Какой слой победил в конкретном месте, статически не вычислить: в
опубликованном CSS есть вложенные @supports, @layer и :where(). Итог
знает только браузер: смотрите вычисленные стили элемента в инструментах
разработчика. Для раскладки есть готовая проверка на странице
(Компонент не раскладывает себя сам).
Смотрите также
- Где объявлены токены — какие токены в каком слое;
- Своя тема проекта — роли и примитивы в CSS проекта;
- Как менять дизайн — что менять, чтобы изменить вид компонентов;
- Цвета — цветовые утилиты;
- Проверки — контракт
core-layer-order.