Перейти к основному содержимому

Каскадные слои @layer

Разработчику Архитектору

Проблема «кто победил в CSS»

В большом проекте стили приходят из:

  • сброса (reset / normalize);
  • библиотеки компонентов;
  • модулей страницы;
  • утилитарных классов;
  • инлайн-правил и !important.

Порядок подключения файлов и специфичность селекторов начинают конфликтовать: один лишний #id ломает кнопку во всём приложении.

@layer вводит явный уровень каскада: сначала решается слой, потом специфичность внутри слоя.

Связь: каскад и специфичность, организация CSS, переменные и темы.


Объявление слоёв

Порядок слоёв задаётся один раз — первым появлением в коде:

@layer reset, base, components, utilities;

Позже можно дописывать правила в уже объявленный слой:

@layer reset {
*, *::before, *::after {
box-sizing: border-box;
}
}

@layer base {
body {
margin: 0;
font-family: system-ui, sans-serif;
line-height: 1.5;
}
}

@layer components {
.btn {
padding: 0.5rem 1rem;
border-radius: 6px;
cursor: pointer;
}
}

@layer utilities {
.hidden {
display: none !important;
}
}

Правило: стиль из utilities перебьёт components при равной специфичности, даже если файл utilities подключён раньше в HTML.


Анонимный слой и импорт

Стили вне @layer имеют приоритет выше любого именованного слоя — поэтому «случайный» CSS в конце файла снова ломает систему. Новый код лучше класть в слой явно.

При @import можно указать слой:

@import url("vendor.css") layer(vendor);

Тогда сторонняя библиотека живёт в vendor между base и components, если так задать порядок:

@layer reset, vendor, base, components, utilities;

Слои и !important

Внутри слоёв !important инвертирует приоритет слоёв для важных деклараций: «важное» из более низкого слоя может победить. На практике в дизайн-системах стараются минимизировать !important в utilities и не смешивать слои хаотично.


Типовая схема (ITCSS / BEM-подобная)

СлойСодержимое
resetbox-sizing, сброс отступов
baseтеги, типографика, :root переменные
components.card, .nav, .form-field
utilities.mt-4, .text-center, .sr-only
@layer components {
.card { padding: 1rem; border: 1px solid #ddd; }
}

@layer utilities {
.p-0 { padding: 0 !important; }
}

Компонент задаёт вид по умолчанию; утилита точечно переопределяет отступ на одной странице — без повышения специфичности до .card.card--special.


@layer и :where()

В селекторах :where нулевая специфичность; в @layer — порядок слоёв. Часто используют вместе: база в base через :where(h1, h2) { … }, компоненты в components с классами.


Когда не усложнять

Для учебной страницы или малого сайта три слоя в одном файле избыточны. @layer окупается при нескольких авторах, UI-kit и долгой жизни проекта.


Краткий итог

@layer задаёт иерархию источников стилей независимо от порядка строк в файле. Объявите порядок слоёв в начале, поместите reset → base → components → utilities, подключайте vendor в свой слой — и уменьшите «войны специфичности».


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).