CSS Layers (@layer)
@layer— правило для создания каскадных слоёв, которые управляют приоритетом стилей вне зависимости от специфичности селекторов и порядка появления.
Зачем нужно
CSS Layers решают главную проблему каскада: конфликт специфичности между вашими стилями и стилями библиотек. С @layer можно гарантировать, что стили вашего проекта всегда перекроют Bootstrap/Tailwind, без !important и без повышения специфичности.
Где используется
- Управление приоритетом: сброс < библиотеки < проект < утилиты
- Интеграция сторонних CSS-библиотек
- Архитектура CSS в крупных проектах (замена ITCSS)
- Изоляция стилей компонентов
Предпосылки
- Каскад и специфичность — как работает каскад
- Подключение стилей — подключение внешних стилей
Создание слоёв
Объявление порядка слоёв
/* Порядок объявления = порядок приоритета (последний побеждает) */
@layer reset, base, components, utilities;
Добавление стилей в слой
@layer reset {
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
}
@layer base {
body {
font-family: system-ui, sans-serif;
line-height: 1.6;
color: #333;
}
h1, h2, h3 {
line-height: 1.2;
}
a {
color: #007bff;
}
}
@layer components {
.button {
padding: 10px 20px;
border: none;
border-radius: 6px;
cursor: pointer;
}
.card {
padding: 20px;
border-radius: 12px;
background: white;
}
}
@layer utilities {
.hidden { display: none; }
.text()-center { text-align: center; }
.mt-4 { margin-top: 16px; }
}
Приоритет слоёв
Низший приоритет ←────────────────→ Высший приоритет
reset → base → components → utilities → НЕ В СЛОЕ
Стили вне слоёв имеют наивысший приоритет и перебивают любой слой.
Слои и специфичность
@layer base {
/* Специфичность: 1-0-0 */
#header .nav a { color: blue; }
}
@layer components {
/* Специфичность: 0-1-0 — НИЖЕ, но слой ВЫШЕ */
.nav-link { color: red; }
}
/* Победит .nav-link (color: red) — слой components > base,
специфичность внутри разных слоёв НЕ сравнивается */
Внутри одного слоя работает обычный каскад (специфичность, порядок). Между слоями — побеждает более поздний слой, игнорируя специфичность.
Импорт в слой
/* Сторонняя библиотека — в свой слой */
@import url("bootstrap.css") layer(vendor);
@import url("custom-lib.css") layer(vendor);
/* Ваши стили — в более приоритетном слое */
@layer vendor, project;
@layer project {
.button {
/* Перебьёт Bootstrap .btn без !important */
background: #e74c3c;
}
}
Вложенные слои
@layer components {
@layer card {
.card { background: white; }
}
@layer button {
.button { background: blue; }
}
}
/* Обращение: components.card, components.button */
@layer components.card {
.card { border-radius: 12px; }
}
Анонимные слои
/* Анонимный слой — к нему нельзя обратиться позже */
@layer {
.temp-style {
color: red;
}
}
Практический пример: архитектура проекта
/* 1. Объявляем порядок слоёв */
@layer reset, vendor, base, layout, components, utilities;
/* 2. Сброс стилей */
@layer reset {
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
}
/* 3. Сторонние библиотеки */
@import url("normalize.css") layer(vendor);
/* 4. Базовые стили */
@layer base {
:root {
--color-primary: #007bff;
--color-text: #333;
--font-family: system-ui, sans-serif;
--radius: 8px;
}
body {
font-family: var(--font-family);
color: var(--color-text);
line-height: 1.6;
}
}
/* 5. Раскладка */
@layer layout {
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
}
/* 6. Компоненты */
@layer components {
.button {
display: inline-flex;
padding: 10px 20px;
border: none;
border-radius: var(--radius);
background: var(--color-primary);
color: white;
cursor: pointer;
}
}
/* 7. Утилиты (высший приоритет среди слоёв) */
@layer utilities {
.hidden { display: none !important; }
.sr-only { /* screen reader only */ }
}
@layer и !important
!important переворачивает порядок слоёв:
@layer base, components;
@layer base {
p { color: red !important; }
}
@layer components {
p { color: blue !important; }
}
/* Без !important: components > base → blue
С !important: base > components → RED (перевёрнутый порядок!) */
Это сделано намеренно: сброс стилей в
@layer resetс!importantимеет наивысший приоритет среди!important-правил.
Частые ошибки
- Стили вне слоёв перебивают всё — если часть стилей не в слое, она побеждает:
@layer components { .button { color: red; } } /* Вне слоя — высший приоритет */ .button { color: blue; } /* Победит */ - Повторное объявление порядка — первое объявление фиксирует порядок:
@layer a, b; /* a < b */ @layer b, a; /* Не изменит порядок! */ !importantв слоях — переворачивает приоритет, что контринтуитивно- Импорт не в слой —
@importбезlayerсоздаёт стили вне слоёв
Практика
- Создать 3 слоя:
reset,base,componentsи проверить приоритет - Импортировать стороннюю библиотеку в слой
vendor - Убедиться, что стиль из
componentsперебиваетbaseдаже с меньшей специфичностью - Попробовать
!importantв слоях и увидеть перевёрнутый порядок - Организовать CSS проекта через слои
Связанные темы
- Каскад и специфичность — как каскад работает с и без слоёв
- Подключение стилей —
@importв слой - CSS Nesting — вложенность внутри слоёв