Каскадные слои появятся в вашем браузере

Каскадные слои ( правило CSS @layer ) появятся в Chromium 99, Firefox 97 и Safari 15.4 Beta. Они обеспечивают более явный контроль над вашими CSS-файлами, чтобы предотвратить конфликты стилей. Это особенно полезно для больших баз кода, систем дизайна и при управлении сторонними стилями в приложениях.

Четкое размещение слоев CSS предотвращает неожиданные переопределения стилей и способствует улучшению архитектуры CSS.

Специфика CSS и каскад

Специфика CSS заключается в том, как CSS решает, какие стили применять к каким элементам. Различные селекторы, которые вы можете использовать, определяют специфику любого правила стиля. Например, элементы менее специфичны, чем классы или атрибуты, которые, в свою очередь, менее специфичны, чем идентификаторы. Это элементарная часть изучения CSS.

Люди обращаются к соглашениям об именах CSS, таким как BEM, чтобы предотвратить непреднамеренное переопределение специфичности. Присвоив всему одно имя класса, все помещается в одну плоскость специфичности. Однако не всегда возможно поддерживать такие организованные стили, особенно при работе со сторонним кодом и системами дизайна.

БЭМ-визуал карточки с классами
Иллюстрированный пример именования БЭМ с сайта Keepuptodate.com.

Каскадные слои призваны решить эту проблему. Они вводят новый уровень в каскад CSS. В многоуровневых стилях приоритет слоя всегда важнее специфики селектора .

Например, селектор .post a.link имеет более высокую специфичность, чем .card a . Если вы попытаетесь стилизовать ссылку внутри карточки или сообщения, вы обнаружите, что будет применен более конкретный селектор.

Используя @layer , вы можете более четко определить специфику стиля каждого из них и убедиться, что стили ссылки вашей карточки переопределяют стили ссылки на публикацию, даже несмотря на то, что специфичность может быть численно ниже, если весь ваш CSS находится в одной плоскости. Это связано с каскадным приоритетом. Многослойные стили создают новые каскадные «плоскости».

Иллюстрация из демо-версии проекта нового пользовательского интерфейса

@layer в действии

Демо, показывающее цвета ссылок при импорте
См. демо на Codepen.

Этот пример демонстрирует возможности каскадных слоев с использованием @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 уровне всегда будут иметь более высокую специфичность, чем правила стиля на уровне типографики. Они больше не будут зелеными ссылками, а будут красными или синими.

Скриншот проекта Codepen
См. демо на Codepen.

Организация импорта

Другой способ использования @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 свои стили, не будет иметь значения для порядка слоев, поскольку он уже установлен в первом экземпляре имени слоя. Это еще одна вещь, о которой стоит беспокоиться меньше. Вы по-прежнему можете присваивать импортированным файлам определенные слои, но порядок уже установлен.

Скриншот проекта Codepen
Изучите проект на Codepen.

Слои и каскад

Давайте сделаем шаг назад и посмотрим, где используются слои по отношению к более широкому каскаду:

Каскадная иллюстрация

Порядок старшинства такой:

  • Пользовательский агент обычный (самый низкий приоритет)
  • Локальный пользователь @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 , чтобы изменить цвет, но он не применяется».

Подробнее о каскадных слоях

Вы также можете просмотреть эти ресурсы, чтобы узнать больше о каскадных слоях: