От автора: существует масса способов именования CSS. Вы, скорее всего, слышали про BEM и SMACSS (последний больше чем просто способ). Также есть OOCSS, больше похожий на целую методику. Все они в значительной степени зависят от селекторов классов CSS из-за их большой универсальности.
Sass помогает писать селекторы классов в модульной форме. С помощью наследования селекторов и mixin’ов мы можем придумывать сумасшедшие API. В этой статье я продемонстрирую (еще раз) пару этих способов и перечислю их плюсы и минусы с моей точке зрения.
Нативное наследование селекторов
Возможность наследовать селекторы, не повторяя оригинальные имена блоков, давно напрашивалась в Sass. И в версии 3.3 эта функция, наконец, была представлена. В бета-версии синтаксис был очень странным, позже с выпуском стабильной версии он был улучшен. В своей статье Natalie Weizenbaum объяснила причины изменения синтаксиса.
В основном селектор-ссылка (&) может использоваться, как часть имени подкласса для создания другого класса от первого родителя на корневом уровне документа (т.е. @at-root не нужен).
1 2 3 4 5 6 7 |
.foo { // Стили для `.foo` &-bar { // Стили для `.foo-bar` } } |
Вскоре этой функцией будут злоупотреблять при написании BEM селекторов, как в крайне популярном медиа-объекте:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.media { // Стили для блока `.media` &__img { // Стили для элемента `.media__image` &--full { // Стили для модифицированного элемента`.media__image--full` } } &--new { // Стили для модификатора`.media--new` } } |
Код выше будет скомпилирован в:
1 2 3 4 |
.media {} .media__img {} .media__img--full {} .media--new {} |
Плюсы
Используются нативные функции. Не нужно никаких дополнительных помощников, таких как переменные или mixin’ы.
В целом достаточно легко разобраться в работе селекторов-ссылок (&).
Минусы
Синтаксис (&) кажется слегка запутанным, если не пугающим для разработчиков, не знакомых с Sass.
Если не использован @at-root, то наследование обычно не распрастраняется на корневой уровень, что может смутить.
BEM mixins
Из-за крайне неудобного синтаксиса генерации классов в бета-версии Sass 3.3 (at-root #{&}__element) для создания более дружелюбных API то тут, то там начали появляться mixin’ы, как замена уродливому синтаксису.
1 2 3 4 5 6 7 8 9 10 11 |
@mixin element($element) { &__#{$element} { @content; } } @mixin modifier($modifier) { &--#{$modifier} { @content; } } |
Вы используете их так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.media { // Стили для `.media` block @include element("image") { // Стили для элемента `.media__image` element @include modifier("full") { // Стили для модифицированного элемента `.media__image--full` } } @include modifier("new") { // Стили для модификатора `.media--new` } } |
По такому же принципу мы могли бы создать блок mixin, но от него не будет пользы, если блок не соответствует одному имени класса. Давайте упростим. Так как некоторым неохота набирать имена модификаторов и элементов, мы вспомнили пару сокращений e и m.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.media { // Стили для блока`.media` @include e("image") { // Стили для элемента `.media__image` @include m("full") { // Стили для модифицированного элемента `.media__image--full` } } @include m("new") { // Стили для модификатора `.media--new` } } |
Плюсы
Если вы знаете, как работает BEM, то вам не составит труда разобраться в API этой версии.
Минусы
Вся логика скрыта под mixin’ами, и если вы не совсем понимаете, как это работает, то совсем не факт, что новые классы и селекторы будут сгенерированны.
Mixin’ы в одну букву скорее всего не самый удачный вариант, иногда сложно понять назначение mixin’а. B и m могут означать все, что угодно.
Очеловеченные-BEM mixin’ы
Недавно я прочел о новом BEM-подобном методе в статье Anders Schmidt Hansen. Основная идея статьи заключается в том, чтобы спрятать жаргон «Блок-Элемент-Модификатор» за общими понятиями, которые и так понятны.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@mixin new($block) { @at-root .#{$block} { @content; } } @mixin has($element) { &__#{$element} { @content; } } @mixin when($modifier) { &--#{$modifier} { @content; } } |
В этом случае вся суть в том, чтобы спрятать код за продуманным mixin’ами таким образом, чтобы это выглядело как код нового mixin’а.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@include new("media") { // Стили для блока `.media` @include has("image") { // Стили для элемента `.media__image` @include when("full") { // Стили для модифицированного элемента `.media__image--full` } } @include when("new") { // Стили для модификатора `.media--new` } } |
Anders пошел еще дальше с is(..) и holds(..) mixin’ами. Вся эта идея отчасти напоминает мне мой when-inside(..) mixin, скрывающий & за дружелюбным mixin’ом во время стилизации элемента, основанного на данном контексте.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@mixin when-inside($selector) { #{$selector} & { @content; } } img { display: block; @include when-inside(".media-inline") { display: inline; } } |
Плюсы
Данный метод делает код более читабельным. Например, когда мы начали называть наши классы состояний с приставкой is- (стало популярным в SMACSS).
До сих пор данный подход придерживается определенной методологии (в нашем случае BEM). Однако, код становится намного дружелюбнее.
Минусы
Больше mixin’ов, больше помощников, необходимо еще больше всего изучить, чтобы во всем разобраться. Никто не любит писать тонны mixin’ов ради простых CSS селекторов.
Для некоторых это может быть слишком абстрактно; не всем нравится читать код по-английски. Зависит от знания языка.
Заключительные рассуждения
Помните, что данные методы обезопасят вас от поиска исходного селектора. И уже тем более, если он совсем не существует, а генерируется Sass. Комментарии перед селекторами решают эту проблему, но почему бы просто не писать селекторы напрямую в одном месте?
В любом случае, это самые популярные способы написания CSS селекторов с помощью Sass, которые я знаю. И между нами: ни один мне не нравится. И не только из-за проблемы с поиском, для меня это не такая и проблема.
Я вижу проблему, которую они пытаются решить, но иногда простота лучше удобства. Повторять корневой селектор не так и сложно, а также делает код более удобным для чтения, т.к. в таком варианте меньше наследований и сам код ближе к стандартному CSS.
Автор: Hugo Giraudel
Источник: //www.sitepoint.com/
Редакция: Команда webformyself.