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

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

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

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

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

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

Визуализация карты с классами в БЭМ
Иллюстрированный пример именования 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 . Файлы normalize, theme и typography в base , файл post в layouts , а cards и footer оба в components . При импорте файла слои создаются с помощью функции layer . Альтернативным подходом было бы организовать ваши слои в верхней части файла, объявив их перед любым импортом:

@layer base,
       theme,
       layouts,
       components,
       utilities;

Теперь порядок, в котором вы @import свои стили, не будет иметь значения для порядка слоев, поскольку он уже установлен в первом экземпляре имени слоя. Это одна проблема, о которой стоит беспокоиться, меньше. Вы по-прежнему можете назначать импортированные файлы определенным слоям, но порядок уже установлен.

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

Слои и каскад

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

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

Порядок приоритета таков:

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

Узнайте больше о каскадных слоях

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