
Практический пример использования CSS Layer / Хабр
Допустим, мы разрабатываем библиотеку компонентов.
Допустим, мы используем React.
Допустим, в ней есть компонент кнопки.
Очень условно он будет выглядеть так:
// Button.js
import ‘./Button.css’
const Button = ({ children, className=»» }) => {
const cls=»Button» + className;
return
}
А стили будут выглядеть так:
/* Button.css */
.Button {
background: blue;
padding: 4px 10px;
border: none;
}
Тут к нам приходят разрабы и говорят: «кнопка классная, но нам нужна ссылка в виде кнопки»
Не вопрос! Добавим свойство Component:
// Button.js
import ‘./Button.css’
const Button = ({ children, Component=»button», className=»» }) => {
const cls=»Button» + className;
return
}
Пример использования:
const linkButton = (
);
Только ой, a ж является инлайновым элементом. Что такого, спросите вы? Кнопка вроде как выглядела, так и выглядит. А вот нет. Представьте, что пользователи в месте встраивания кнопки хотят добавить ей отступ справа:
// App.js
/* App.css */
.myButton {
margin-right: 10px;
}
Инлайновый элемент проигнорирует этот margin.
Ну ничего, и не с такими сложностями мы справлялись. Внесем изменение в стиль кнопки:
/* Button.css */
.Button {
background: blue;
padding: 4px 10px;
border: none;
display: inline-block; /* Зафиксируем display */
}
Но теперь возникла другая беда, куда более подлая и трудноизлечимая. Следите за руками. Представьте себе такой способ использования кнопки в проекте. Допустим, там есть какой-то стейт loading, который если true, то кнопку нужно скрыть:
// App.js
/* App.css */
.hidden {
display: none;
}
Вспоминаем, как работает каскад в CSS. Если вдруг забыли, то вот отличная статья, поясняющая за все уровни каскадов. Прочитали? Возвращаемся к нашей беде.
Беда заключается в том, что у .hidden и .Button одинаковый вес, при этом оба они претендуют на свойство display. А значит CSS-парсеру придется выяснять победителя исходя из порядка. Порядок — это последний уровень каскада. Когда ваши CSS-файлы разбиты по модулям, рассчитывать на их определенный порядок появления в итоговом бандле очень некомфортно. В итоге это будет приводить к ситуациям, когда побеждает то один селектор, то другой. Что же делоть…
Layer спешит на помощь
Новый уровень каскада Layer разместился аккурат перед специфичностью и порядком:
-
Importance
-
Context
-
Layer (приветик)
-
Specificity
-
Order
Layer позволяет гибко задать разные уровни собственных стилей. В нашем примере таких уровней может быть три (а может быть и больше):
-
уровень сброса стилей;
-
уровень стилей библиотеки;
-
уровень стилей приложения.
Давайте эти уровни зададим.
@layer reset, library; /* Деклалируем приоритет слоёв */
/* Button.css */
@layer reset {
.Button {
display: inline-block;
}
}
@layer library {
.Button {
background: blue;
padding: 4px 10px;
border: none;
}
}
Но постойте, мы вроде хотели три уровня задать, а задали два. Это специфика каскада layer. Всё, что определено за пределами какого-либо уровня, автоматически становится самым приоритетным. На самом деле и library тут не нужен, но я его оставил для наглядности.
Прикольно, что все стили вне уровней побеждают, так как пользователям не нужно свои перебивающие стили обрамлять в какой-нибудь @layer app.
То есть вот этот стиль в итоге перебьёт тот, что находится в @layer reset.
/* App.css */
.hidden {
display: none; /* Наш победитель */
}
Удобно? По моему это просто фантастика. Во многом потому, что в браузерах этого каскада ещё нет 🙁 пока.


