Кратко
СкопированоДиректива @layer
, дополнительная функция layer
и ключевое слово layer
дают вам возможность управлять каскадными слоями.
Каскадные слои — способ группировки и порядок применения стилей в одном источнике. Они помогают браузерам понять, какие стили применить на сайте.
Источник в CSS — место, откуда браузер берёт CSS-правила. Это могут быть ваши стили на сайте, настройки пользователей в браузере и системе, а также браузерные стили по умолчанию. Подробнее об этой и других концепциях в статье «Принцип каскада».
Пример
СкопированоБлагодаря каскадным слоям вы напрямую управляете слоями с разными наборами CSS-правил и решаете, какие стили специфичнее и в каком порядке их применять. Так что они пригодятся для:
- сброса браузерных стилей по умолчанию;
- перезаписи стилей из CSS-фреймворков и библиотек;
- стилизации компонентов;
- хранения стилей в одном месте, например, для состояний интерактивных элементов;
- цветовых тем, схем и поддержки разных режимов передачи цветов.
Например, вот стили с @layer
для состояния кнопки при фокусе и когда она неактивна. В слое states
устанавливаем стили для :disabled
и :focus
, а в components
— стили кнопки по умолчанию.
@layer components, states;@layer components { .button { display: block; min-width: 210px; border: 2px solid transparent; border-radius: 6px; padding: 9px 15px; color: #000000; font-size: 18px; font-weight: 300; font-family: inherit; transition: background-color 0.2s linear; } .button:hover { background-color: #FFFFFF; cursor: pointer; transition: background-color 0.2s linear; }}@layer states { :focus-visible { border: 2px solid #FFFFFF; outline: none; } :disabled { background-color: #DDDDDD; }}
@layer components, states; @layer components { .button { display: block; min-width: 210px; border: 2px solid transparent; border-radius: 6px; padding: 9px 15px; color: #000000; font-size: 18px; font-weight: 300; font-family: inherit; transition: background-color 0.2s linear; } .button:hover { background-color: #FFFFFF; cursor: pointer; transition: background-color 0.2s linear; } } @layer states { :focus-visible { border: 2px solid #FFFFFF; outline: none; } :disabled { background-color: #DDDDDD; } }
Без каскадных слоёв нам нужно задать стили классу .button
с нужными псевдоклассами. При этом мы не можем хранить их в одном месте файла так, чтобы их случайно не перезаписали другие разработчики.
.button { /* Нужные CSS-правила */}.button:hover { /* Нужные CSS-правила */}.button:focus-visible { /* Нужные CSS-правила */}.button:disabled { /* Нужные CSS-правила */}
.button { /* Нужные CSS-правила */ } .button:hover { /* Нужные CSS-правила */ } .button:focus-visible { /* Нужные CSS-правила */ } .button:disabled { /* Нужные CSS-правила */ }
С каскадными слоями легче победить сторонние стили. Например, из Bootstrap. Представим, что хотим изменить размер заголовка первого уровня без мучительных поисков нужных Sass-переменных.
<h1 class="fs-1">Последние обновления</h1>
<h1 class="fs-1">Последние обновления</h1>
Стили Bootstrap:
.fs-1 { font-size: 2.5rem !important;}
.fs-1 { font-size: 2.5rem !important; }
Наши стили с использованием каскадных слоёв:
@import url("https://cdn.com/bootstrap.min.css") layer;@layer { .fs-1 { font-size: 3rem; }}
@import url("https://cdn.com/bootstrap.min.css") layer; @layer { .fs-1 { font-size: 3rem; } }
Со старыми возможностями CSS эту проблему приходится решать несколькими способами. Например, модификатором !important
.
.fs-1 { font-size: 3rem !important;}
.fs-1 { font-size: 3rem !important; }
Как пишется
СкопированоЕсть несколько способов объявления каскадных слоёв:
- директива
@layer
; - ключевое слово
layer
; - функция
layer
.( )
Слои могут быть с именем (именованными) и без него (анонимными).
С помощью именованных слоёв вы напрямую управляете порядком стилей или определяете его в одном месте CSS-файла.
Анонимные слои не дают другим разработчикам манипулировать правилами в них и гарантируют, что все нужные правила хранятся в одном месте файла. Это особенно полезно, когда заменяете стили из CSS-фреймворка на свои.
После компиляции стилей с каскадными слоями, вы получаете обычный CSS-код. В инструменте разработчика заметите, что ваши стили берутся из файла проекта. Также у правил указано, что это за слой и как называется. Например, «Layer typography» или стили браузера «Layer user agent stylesheet».
Директива @layer
СкопированоДля именованных слоёв укажите имя после директивы @layer
, а внутри перечислите нужные правила. Имя слоя может быть любым на латинице. К примеру, application
, framework
, base
, utilities
, typography
или theme
. Имена должны быть уникальными и не повторяться. Исключение — слои, вложенные в другие.
@layer any-layer-name { /* Одно или несколько CSS-правил */}
@layer any-layer-name { /* Одно или несколько CSS-правил */ }
Слои можно вкладывать друг в друга — группировать. Слой с другими внутри называется родительским, а вложенные в него — дочерними. Обратите внимание, что дочерний слой не может «выйти за пределы» своего родителя. Его не связать с другими дочерними и даже родительскими каскадными слоями.
Здесь слой framework
— родительский, а base
и theme
— дочерние:
@layer framework { @layer base { /* Одно или несколько CSS-правил */ } @layer theme { /* Одно или несколько CSS-правил */ }}
@layer framework { @layer base { /* Одно или несколько CSS-правил */ } @layer theme { /* Одно или несколько CSS-правил */ } }
У дочерних слоёв могут быть такие же имена, как у других за пределами его родителя. В этом примере два совершенно разных слоя с именами base
и framework
, так как второй слой base
находится внутри framework
:
@layer base { /* Одно или несколько CSS-правил */}@layer framework { @layer base { /* Одно или несколько CSS-правил */ }}
@layer base { /* Одно или несколько CSS-правил */ } @layer framework { @layer base { /* Одно или несколько CSS-правил */ } }
Слои можно перечислять в одном месте. Расположите их имена через запятую после директивы @layer
. Тут собрали два слоя в одной строке и получили @layer layer
.
@layer layer-1, layer-2;@layer layer-1 { /* Одно или несколько CSS-правил */}@layer layer-2 { /* Одно или несколько CSS-правил */}
@layer layer-1, layer-2; @layer layer-1 { /* Одно или несколько CSS-правил */ } @layer layer-2 { /* Одно или несколько CSS-правил */ }
Когда перечисляете дочерние слои в одну строку, сначала укажите название родительского, а через точку — дочернего. К примеру, у нас есть родительский слой framework
и дочерние base
и theme
. При перечислении имена детей будут framework
и framework
:
@layer framework.base, framework.theme;@layer framework { @layer base { /* Одно или несколько CSS-правил */ } @layer theme { /* Одно или несколько CSS-правил */ }}
@layer framework.base, framework.theme; @layer framework { @layer base { /* Одно или несколько CSS-правил */ } @layer theme { /* Одно или несколько CSS-правил */ } }
Слои можно перечислять и внутри @layer
. В этом случае название слоя снова складывается из имени родителя и ребёнка. Например, в слое framework
определяем порядок применения базовых стилей base
и стилей для тёмной темы theme
. Сами CSS-правила храним в отдельных слоях framework
и framework
:
@layer framework { @layer base, theme;}@layer framework.base { /* Одно или несколько CSS-правил */}@layer framework.theme { /* Одно или несколько CSS-правил */}
@layer framework { @layer base, theme; } @layer framework.base { /* Одно или несколько CSS-правил */ } @layer framework.theme { /* Одно или несколько CSS-правил */ }
В @layer
можно вкладывать и другие директивы. К примеру, @media
.
@layer framework { html { color: #000000; background: #FFFFFF; } @media (prefers-color-scheme: dark) { html { color: #FFFFFF; background: #000000; } }}
@layer framework { html { color: #000000; background: #FFFFFF; } @media (prefers-color-scheme: dark) { html { color: #FFFFFF; background: #000000; } } }
Для анонимных слоёв указывайте только директиву @layer
с нужными правилами внутри.
@layer { /* Одно или несколько правил */}
@layer { /* Одно или несколько правил */ }
В анонимные слои можно вкладывать именованные. Другие разработчики всё ещё не могут манипулировать стилями в них, так как их родитель остаётся анонимным. Здесь внутри анонимного слоя находятся два дочерних base
и typography
:
@layer { @layer base { /* Одно или несколько правил */ } @layer typography { /* Одно или несколько правил */ }}
@layer { @layer base { /* Одно или несколько правил */ } @layer typography { /* Одно или несколько правил */ } }
Как работает
СкопированоНа то, в каком порядке применяются стили слоёв, влияет порядок их расположения в файле или списке. Также есть особенности поведения CSS-правил и внутри них.
В слое с CSS-правилами и ещё одним @layer
выигрывают отдельные правила. В этом примере текст параграфа будет чёрным (#000000
), так как селектор с этим правилом за пределами вложенного слоя:
<p class="text--pink"> Неограниченный семиозис симулякров.</p>
<p class="text--pink"> Неограниченный семиозис симулякров. </p>
@layer typography { /* Я победил 🥇 */ p { color: #000000; } /* Я проиграл */ @layer content;}@layer typography.content { p { color: #FFFFFF; }}
@layer typography { /* Я победил 🥇 */ p { color: #000000; } /* Я проиграл */ @layer content; } @layer typography.content { p { color: #FFFFFF; } }
Чтобы избежать путаницы, можно всегда выносить такие правила за пределы @layer
:
/* Я проиграл */@layer typography { @layer content;}@layer typography.content { p { color: #FFFFFF; }}/* Я победил 🥇 */p { color: #000000;}
/* Я проиграл */ @layer typography { @layer content; } @layer typography.content { p { color: #FFFFFF; } } /* Я победил 🥇 */ p { color: #000000; }
Когда правила не вложены внутрь @layer
, они всегда побеждают. Например, тут текст будет чёрным, несмотря на стили для класса .text
в @layer
:
<p class="text--pink"> Хроносинкластический инфундибулум.</p>
<p class="text--pink"> Хроносинкластический инфундибулум. </p>
/* Я проиграл */@layer typography { .text--pink { color: #F498AD; }}/* Я победил 🥇 */p { color: #000000;}
/* Я проиграл */ @layer typography { .text--pink { color: #F498AD; } } /* Я победил 🥇 */ p { color: #000000; }
Отдельное правило применится даже если расположено выше @layer
, так что текст всё ещё чёрный:
/* Я победил 🥇 */p { color: #000000;}/* Я проиграл */@layer typography { .text--pink { color: #F498AD; }}
/* Я победил 🥇 */ p { color: #000000; } /* Я проиграл */ @layer typography { .text--pink { color: #F498AD; } }
А что, если в слоях есть правила с модификатором !important
? В этом случае порядок определяется так:
- Слой с
@layer
со свойством!important
, который расположен выше других. - CSS-правило вне
@layer
. - Слой с
@layer
без свойств с!important
.
Здесь побеждает розовый цвет текста с модификатором !important
из слоя typography
:
<p class="text--pink"> Мутуализм, комменсализм, паразитизм.</p>
<p class="text--pink"> Мутуализм, комменсализм, паразитизм. </p>
/* Я победил 🥇 */@layer typography { .text--pink { color: #F498AD !important; }}/* Я проиграл */p { color: #000000 !important;}/* Я тоже проиграл */@layer typography { p { color: #FFFFFF !important; }}
/* Я победил 🥇 */ @layer typography { .text--pink { color: #F498AD !important; } } /* Я проиграл */ p { color: #000000 !important; } /* Я тоже проиграл */ @layer typography { p { color: #FFFFFF !important; } }
Когда перечисляете слои в одну строку, важен их порядок. Первый слой в списке перезаписывается слоем после него и так далее.
В примере текст параграфа <p>
снова будет чёрным, так как слой layer
находится после layer
и поэтому выше в порядке представления:
@layer layer-1, layer-2;/* Я проиграл */@layer layer-1 { p { color: #FFFFFF; }}/* Я победил 🥇 */@layer layer-2 { p { color: #000000; }}
@layer layer-1, layer-2; /* Я проиграл */ @layer layer-1 { p { color: #FFFFFF; } } /* Я победил 🥇 */ @layer layer-2 { p { color: #000000; } }
Даже если повысить специфичность параграфа из layer
с помощью id
, layer
всё равно победит. Так что текст в параграфе останется чёрным:
@layer layer-1, layer-2;/* Я проиграл */@layer layer-1 { p#light { color: #FFFFFF; }}/* Я победил 🥇 */@layer layer-2 { p { color: #000000; }}
@layer layer-1, layer-2; /* Я проиграл */ @layer layer-1 { p#light { color: #FFFFFF; } } /* Я победил 🥇 */ @layer layer-2 { p { color: #000000; } }
Перечисление дочерних слоёв в одну строку работает так же. В этом примере есть родитель framework
и два ребёнка framework
и framework
. Текст параграфа снова будет чёрным, так как framework
в списке находится после framework
:
@layer framework.base, framework.theme;@layer framework { /* Я победил 🥇 */ @layer theme { p { color: #000000; } } /* Я проиграл */ @layer base { p { color: #FFFFFF; } }}
@layer framework.base, framework.theme; @layer framework { /* Я победил 🥇 */ @layer theme { p { color: #000000; } } /* Я проиграл */ @layer base { p { color: #FFFFFF; } } }
Для анонимных слоёв важно, где они находятся в файле. Так что вы не можете добавить их в любое место, как именованные. Ниже анонимный слой расположен перед именованным base
, поэтому текст параграфа — чёрный:
/* Я проиграл */@layer { p { color: #FFFFFF; }}/* Я победил 🥇 */@layer base { p { color: #000000; }}
/* Я проиграл */ @layer { p { color: #FFFFFF; } } /* Я победил 🥇 */ @layer base { p { color: #000000; } }
Если расположить анонимный слой после именованного base
, текст станет белым (#
):
/* Я проиграл */@layer base { p { color: #000000; }}/* Я наконец-то победил 🥇 */@layer { p { color: #FFFFFF; }}
/* Я проиграл */ @layer base { p { color: #000000; } } /* Я наконец-то победил 🥇 */ @layer { p { color: #FFFFFF; } }
Ключевое слово layer
СкопированоКлючевое слово layer
нужно, когда применяете правила анонимных слоёв при импорте стилей из другого файла. Это делают с помощью директивы @import
.
Укажите слово layer
после @import
и пути к нужному CSS-файлу. Чтобы другие стили и разработчики точно не перезаписали правила из анонимного слоя, расположите его в самом конце файла. Этот трюк помогает собрать в одном месте самые важные и базовые стили, которые не хотите изменять ни при каких обстоятельствах.
Здесь заменяем нужные стили из файла tailwind.css на стили из анонимного слоя:
@import url(tailwind.css) layer;@layer { /* Одно или несколько правил */}
@import url(tailwind.css) layer; @layer { /* Одно или несколько правил */ }
Можете расположить анонимный слой и перед строкой с @import
. В этом случае приоритет этих стилей будет ниже, чем у слоёв за ними.
@layer { /* Одно или несколько правил */}@import url(tailwind.css) layer;
@layer { /* Одно или несколько правил */ } @import url(tailwind.css) layer;
Правила из одного анонимного слоя можно применять несколько раз. Давайте используем стили из анонимного слоя в файлах base-forms.css, base-links.css и base-buttons.css:
@import url(base-forms.css) layer;@import url(base-links.css) layer;@import url(base-buttons.css) layer;@layer { /* Одно или несколько правил */}
@import url(base-forms.css) layer; @import url(base-links.css) layer; @import url(base-buttons.css) layer; @layer { /* Одно или несколько правил */ }
Функция layer()
СкопированоС помощью функции layer
вы обращаетесь к конкретному слою при импорте стилей из одного файла в другой.
Представим, что нужно добавить свои базовые стили для сайта, на котором уже используем CSS-фреймворк, например, Bootstrap. Создадим слой base
с нужными CSS-правилами и применим их в bootstrap.css:
@import url(bootstrap.css) layer(base);@layer base { /* Одно или несколько правил */}
@import url(bootstrap.css) layer(base); @layer base { /* Одно или несколько правил */ }
layer
даёт повторно использовать стили из одного и того же именованного слоя. Здесь стили из base
объединяются с другими из файлов headings.css и links.css:
@import url(buttons.css) layer(base);@import url(links.css) layer(base);@layer base { /* Одно или несколько правил */}
@import url(buttons.css) layer(base); @import url(links.css) layer(base); @layer base { /* Одно или несколько правил */ }
Функция также пригодится, когда нужен определённый дочерний слой внутри анонимного. Представим, что добавляем свои базовые стили для сайта, на котором снова используем Bootstrap. Создадим дочерний слой base
внутри анонимного и обратимся прямо к нему с помощью layer
:
@import url(bootstrap.css) layer(base);@layer { @layer base { /* Одно или несколько правил */ }}
@import url(bootstrap.css) layer(base); @layer { @layer base { /* Одно или несколько правил */ } }
Всё вместе
СкопированоДирективу, функцию и ключевое слово можно совмещать. Так вы сможете точнее определить порядок слоёв в одном месте перед объявлением стилей.
В начале файла перечислим слои после @layer
. Расположим их так, чтобы у слоя tailwind
для перезаписи сторонних стилей был более низкий приоритет, а у application
для собственных стилей — самый высокий. На второй строке импортируем стили из tailwind.css и перезапишем нужные слоем tailwind
с помощью layer
. После этого уже определим нужные нам CSS-правила.
@layer default, tailwind, application;@import url(tailwind.css) layer(tailwind);@layer default { /* Одно или несколько правил */}@layer application { /* Одно или несколько правил */}@layer tailwind { /* Одно или несколько правил */}
@layer default, tailwind, application; @import url(tailwind.css) layer(tailwind); @layer default { /* Одно или несколько правил */ } @layer application { /* Одно или несколько правил */ } @layer tailwind { /* Одно или несколько правил */ }
@import
можно разместить между строками с @layer
. Результат будем одинаковым.
@layer default;@import url(tailwind.css) layer(tailwind);@layer application;@layer default { /* Одно или несколько правил */}@layer application { /* Одно или несколько правил */}@layer tailwind { /* Одно или несколько правил */}
@layer default; @import url(tailwind.css) layer(tailwind); @layer application; @layer default { /* Одно или несколько правил */ } @layer application { /* Одно или несколько правил */ } @layer tailwind { /* Одно или несколько правил */ }
Если нужно применить несколько слоёв в импортированном файле, перечислите их через запятую на одной строке с @import
. Спецификация запрещает импортировать другие файлы после однострочного @layer
.
@layer default;@import url(frameworks.css) layer(bootstrap), layer(tailwind);@layer application;@layer default { /* Одно или несколько правил */}@layer application { /* Одно или несколько правил */}@layer bootstrap { /* Одно или несколько правил */}@layer tailwind { /* Одно или несколько правил */}
@layer default; @import url(frameworks.css) layer(bootstrap), layer(tailwind); @layer application; @layer default { /* Одно или несколько правил */ } @layer application { /* Одно или несколько правил */ } @layer bootstrap { /* Одно или несколько правил */ } @layer tailwind { /* Одно или несколько правил */ }
Как понять
СкопированоКаскадные слои в CSS похожи на слои из редакторов изображений вроде PhotoShop. Для картинок можно добавить несколько слоёв, чтобы гибче управлять разными эффектами и фильтрами. Так как слои прозрачные и не смешиваются друг с другом, легко исправить ошибку или добавить новый эффект без изменения старого.
@layer
, layer
и layer
решают проблемы со стилями без изменения селекторов, а также помогают избежать конфликты между разными слоями из-за их положения в CSS-файлах. Часто эти проблемы появляются из-за нескольких источников стилей. Например, фреймворков и библиотек, которые в основном используют в больших проектах.