SCSS: Стилизация элементов модифицированного блока
Давайте представим, что у нас есть вот такой простенький HTML-компонент, который мы планируем повторно использовать в нашем приложении. Классы именуем так, как это рекомендует делать методология БЭМ.
<div class="block">
<h2 class="block__title">Заголовок</h2>
<p class="block__description">Описание</p>
</div>
Далее стилизуем наш компонент, используя для этого препроцессор SCSS:
.block {
border: 1px solid red;
&__title {
color: black;
}
&__description {
color: blue;
}
}
Отлично, наш компонент готов. Представим, что где-то в приложении, он должен выглядеть иначе, например, иметь другие цвета у бордера, заголовка и описания.
Так как мы знаем и используем БЭМ, чтобы задать другие стили, идём и добавляем модификатор --secondary
для нашего блока:
<div class="block block--secondary">
<h2 class="block__title">Заголовок</h2>
<p class="block__description">Описание</p>
</div>
Теперь, когда у нас есть класс-модификатор
, необходимо его стилизовать.
Добавляем стили
Стилизовать элементы блока с модификатором в SCSS можно аж несколькими способами. Когда я впервые познакомился с SCSS и столкнулся с такой задачей, первое, что я написал, выглядело как-то так:
.block {
&--secondary {
border-color: green;
&__title {
color: white;
}
&__description {
color: pink;
}
}
}
Конечно же, это не сработало, что вполне логично. Если взглянуть на итоговый CSS, сразу станет ясно почему:
.block--secondary {
border-color: green;
}
.block--secondary__title {
color: white;
}
.block--secondary__description {
color: pink;
}
Одиночный и двойной амперсанды
Наверное, самым простым, но не самым оптимальным решением будет стилизация блока и его элементов отдельно друг от друга с использованием амперсанда:
.block {
&--secondary {
border-color: green;
}
&--secondary & {
&__title {
color: white;
}
&__description {
color: pink;
}
}
}
Именно этот подход я использую в своей работе, так как он кажется мне наиболее понятным и лаконичным. Однако, как мы видим, он неидеальный.
Во-первых, нам приходиться отдельно стилизовать сам блок с модификатором и его элементы. Что приводит к дублированию названия модификатора в стилях.
Во-вторых, при таком подходе мы теряем полноценную вложенность и привязку к классу блока.
Переменные
Переменные в SCSS это очень мощный инструмент который позволяет делать какие-то невероятные вещи. В том числе их можно использовать для стилизации элементов модифицированного блока.
$block: block;
.#{$block} {
.#{$block}--secondary {
border-color: green;
.#{$block}__title {
color: white;
}
.#{$block}__description {
color: pink;
}
}
}
Такая запись, в отличие от предыдущего примера, позволяет нам сохранить полноценную вложенность классов в скомпилированном CSS, сравните:
/*С амперсандом*/
.block--secondary .block__description {
color: pink;
}
/*С переменной*/
.block .block--secondary .block__description {
color: pink;
}
Однако, этот подход, на мой взгляд, уже не так прост для быстрого восприятия, плюс нам нужно выносить переменную класса отдельно.
Чтобы не выносить переменную, можно написать вот так:
.block {
$parent: &;
#{$parent}--secondary {
color: blue;
#{$parent}__title {
color: white;
}
#{$parent}__description {
color: pink;
}
}
}
Как точно не нужно делать
Самое неудачное, на мой взгляд, решение — явное указание класса элемента. Если мы захотим изменить класс блока, кроме HTML, менять придётся ещё и стили. В итоге теряется смысл использования препроцессора.
.block {
&--secondary {
border-color: green;
.block__title {
color: white;
}
.block__description {
color: pink;
}
}
}