Статья посвящена вопросу “тихих” placeholder’ов в препроцессоре Sass. Что это такое и в чем преимущество их использования.
Оригинал статьи размещен здесь - Understanding placeholder selectors.
Препроцессор Sass предоставляет несколько способов создания одного фрагмента кода, который будет многократно использоваться внутри CSS-кода.
Например, можно воспользоваться миксинами (
) для вставки группы CSS-свойств (или CSS-правил) в CSS-коде.1
mixins
Или же использовать директиву
для расширения набора CSS-свойств одного HTML-элемента за счет CSS-свойств другого HTML-элемента.1
@extend
В Sass версии 3.2 введена новая концепция под названием
, которая делает использование директивы 1
placeholder
еще более эффективным способом.1
@extend
Но прежде чем мы перейдем к рассмотрению этого нововведенния, давайте остановимся на моменте, каким образом работает расширение (
) CSS-свойств в Sass.1
@extend
Как работает @extend
Директива
в препроцессоре Sass позволяет CSS-селекторам с легкостью обмениваться между собой своими CSS-свойствами. Лучше всего вышесказанное можно проиллюстрировать на живом примере:1
@extend
Результатом компиляции этого SCSS-кода в CSS-код будет следующий фрагмент:
Рассмотрим “механизм” показанного выше примера более детально. В нем директива
играет ключевую роль. С помощью нее селекторы 1
@extend
и 1
.error-icon
наследуют свойства селектора 1
.info-icon
. При изменении CSS-свойств селектора 1
.icon
автоматически будут меняться свойства селекторов 1
.icon
и 1
.error-icon
, так как они наследуют определенный набор CSS-свойств у селектора 1
.info-icon
. Довольно изящный подход, не правда ли?1
.icon
А вот теперь наступает интересный момент. Что, если элемент с классом
не планируется использовать и он даже не будет присутствовать в HTML-разметке? Но CSS-свойства этого элемента нам нужны для стилизации элементов 1
.icon
и 1
.error-icon
.1
.info-icon
Получается, что результирующий CSS-код будет неоправданно раздут из-за того, что в нем присутствует “лишний” элемент, который напрямую никогда не будет использован.
И тут наступает момент для выхода на сцену героя этой статьи - селектора
(его еще называют “тихим” 1
placeholder
‘ом):1
placeholder
Знакомимся с селектором placeholder
Селекторы
были введены в Sass как раз для того, чтобы решать вышеназванную проблему. Синтаксис 1
placeholder
очень похож на синтаксис обычных CSS-классов, только вместо точки (1
placeholder
) перед именем ставиться символ процента 1
.
.1
%
Селекторы
имеют одну специфичную для них особенность - они никак не проявляют себя в скомпилированном CSS-коде. Можно сказать по другому - вы никогда не найдете селекторов 1
placeholder
в результирующем CSS-коде (поэтому они и носят такое название - “тихие” 1
placeholder
). В скомпилированном CSS-коде будут только селекторы, которые используют “тихие” 1
placeholder
‘ы, но никак не сами “тихие” 1
placeholder
‘ы.1
placeholder
Вернемся назад, к нашему начальному примеру. Заменим в нем имя класса
на имя “тихого” placeholder’а - 1
.icon
:1
%icon
В результате скомпилированный CSS-код будет выглядеть таким образом:
Обратите внимание на важный момент - класс
теперь не присутствует в результирующем CSS-коде! Его там нет!1
.icon
@extend или @include
На первый взгляд может показаться, что “тихие”
- это почти тоже самое, что и миксины (1
placeholder
). С функциональной точки зрения такое утверждение абсолютно верно - результат в браузере получается идентичным. А вот с точки зрения CSS разница очень существенная!1
mixin
Давайте снова изменим наш первоначальный пример и теперь воспользуемся миксином
:1
@mixin icon
Посмотрим на сгенерированный CSS-код:
С точки зрения разработки данный пример ничем не хуже примера с использованием “тихого”
‘а.1
placeholder
Но обратите внимание на тот факт, что CSS-правила
и 1
transition: background-color ease .2s;
дублируются между селекторами 1
margin: 0 .5em;
и 1
.error-icon
, что приводит к неоправданному раздутию кода. В случае использования “тихого” 1
.info-icon
этого не происходит.1
placeholder
Ограничения
Использование директивы
имеет одно ограничение, связанное с тем, что применение “тихих” 1
@extend
‘ов никак не оправдывает себя в медиа-запросах 1
placeholder
.1
@media
Рассмотрим такой пример:
Видим, что в данном случае “тихий”
добавлен для селекторов, находящихся внутри медиа-запроса 1
placeholder
.1
@media
Однако, при попытке компиляции этого SCSS-кода в CSS-код получиться ошибка:
You may not @extend an outer selector from within @media. You may only @extend selectors within the same directive. From “@extend %icon” on line 8 of icons.scss
Когда я первый раз увидел такую ошибку, то подумал, что это баг. Но по зрелом размышлении пришел к выводу, что в данном подходе все правильно.
Механизм работы директивы
основан на добавлении одного селектора к другому селектору без необходимости дублировать CSS-свойства этих селекторов. Однако невозможно объединять селекторы, находящиеся в разных медиа-запросах 1
@extend
.1
@media
Но можно поступить по другому, чтобы выйти из данной затруднительной ситуации. Любой медиа-запрос, который служит оберткой для “тихого”
, распространяют свои свойства на селекторы, не размещенные внутри этого запроса.1
placeholder
Выражение достаточно запутанное, поэтому лучше приведу пример:
Компиляция пройдет без ошибок и ее результатом будет CSS-код:
Заключение
Обе директивы
и 1
@extend
являются очень полезными инструментами, между которыми существует тонкое различие. Если вопрос производительности генерируемого CSS-кода имеет для вас важное значение или же перед вами стоит проблема повторяемости кода, то решением будет являться директива 1
@include
. В некоторых случая 1
@extend
значительно упрощает получаемый CSS-код и улучшает его производительность.1
@extend
Конечно же, ничто не мешает вам смешивать между собой директиву
и миксин 1
@extend
(если этого требуют обстоятельства):1
mixin
Однако, в разработке я придерживаюсь такого подхода, когда исходный код легко читается и поддерживается.