Статьи

Что никто не сказал вам о Sass’s @extend

Sass предоставляет множество мощных функций для написания последовательного и надежного CSS. @extend один из самых мощных, но хитрых. Хотя большинство пользователей Sass понимают основы @extend , я чувствую, что есть еще несколько неясных частей, которые не так хорошо известны.

Но сначала давайте начнем с основ.

Основы @extend

Директива Sass @extend предоставляет простой способ позволить селектору наследовать стили другого. Это особенно полезно в архитектуре CSS на основе компонентов, что позволяет нам легко вносить изменения в компонент путем его расширения.

Смотреть AtoZ: Sass
Узнайте Sass буква за буквой

Многие из вас, возможно, уже знают, как расширить селектор, но для тех, кто этого не делает, вот самый основной случай расширения селектора в Sass:

 .message { padding: .5em; } .message-error { @extend .message; } 

В результате получается следующий CSS:

 .message, .message-error { padding: .5em; } 

Легко, правда? Конечно, вы не ограничены расширением классов; Вы можете расширять селекторы тегов (например, a ), идентификаторы (например, #id ) — практически любой действительный селектор CSS. И вы можете расширить Sass заполнители (например, %placeholder ), которые явно созданы для этого.

Примечание: в предыдущей статье Sass: Mixin или Placeholder? Я затронул тему заполнителя более подробно. Вы также можете проверить заполнитель на официальных документах Sass .

Расширение более глубокого селектора

В большинстве случаев вы расширяете очень простые селекторы (в основном, классы), но ничто не мешает вам расширить более сложный селектор, такой как .class element:pseudo или даже:

 .message + .message { margin-bottom: .5em; } .message-error { @extend .message; } 

Что бы вывести:

 .message + .message, .message-error + .message-error, .message + .message-error, .message-error + .message { margin-bottom: .5em; } 

Результат теперь немного сложнее, но если вы понимаете @extend , вывод не должен вас сильно удивлять.

Несколько расширяет

Возможно, вы знаете, что можете расширить несколько селекторов из одного правила, но знаете ли вы, что можете сделать это с помощью одной директивы @extend ?

 .message { padding: .5em; } .important { font-weight: bold; } .message-error { @extend .message, .important; } 

Выход:

 .message, .message-error { padding: .5em; } .important, .message-error { font-weight: bold; } 

Если вы спросите меня, я не предпочитаю этот метод. Хотя это делает код немного короче, мне труднее его читать. Использование различных директив для каждого расширенного селектора позволяет глазу определить селекторы и их количество.

Вы можете обойти синтаксис следующим образом:

 .message-error { @extend .message, .important; } 

Но насколько это более читабельно?

Я буду продолжать использовать одну директиву @extend на строку, но результат будет таким же, так что не стесняйтесь выбирать синтаксис, который вам наиболее удобен.

Цепочка расширяется

Как только что обсуждалось, селектор может @extend из нескольких источников. Но вы также можете @extend свои директивы @extend :

 .message { padding: .5em; } .message-important { @extend .message; font-weight: bold; } .message-error { @extend .message-important; } 

И вывод:

 .message, .message-important, .message-error { padding: .5em; } .message-important, message-error { font-weight: bold; } 

Хотя приведенный выше пример действителен, я бы посоветовал не делать этого, поскольку он может иметь нежелательные последствия. Давайте обсудим это прямо сейчас.

Массивное расширение

Вероятно, один из главных аргументов против препроцессоров CSS: «Посмотрите на результат, это ужасно!» В некотором смысле, они правы. Директива Sass @extend настолько мощна, что может привести к необычно большим расширениям .

Вот почему вы всегда должны быть осторожны при расширении селектора, потому что он расширит все вхождения селектора — что может быстро запутаться. Рассмотрим следующий пример:

 .important { font-weight: bold; } .sidebar .important { color: red; } .message { @extend .important; } 

Это выведет:

 .important, .message { font-weight: bold; } .sidebar .important, .sidebar .message { color: red; } 

Как видите, не только .message унаследован от .message но .message также унаследован от случаев, когда .important используется также в селекторе-потомке. Хотя это может быть тем, чего вы ожидаете, это не всегда так, поэтому вы должны осторожно использовать директиву @extend . Либо убедитесь, что селектор, из которого вы расширяете, существует только в одном месте в вашем CSS, либо расширьте местозаполнитель — вот для чего они.

Так что имейте в виду, что Sass не создает плохой код, а плохие кодеры .

Сохранение исходного порядка

Одна очень малоизвестная характеристика @extend в Sass — это то, как он работает с порядком исходного кода. Давайте посмотрим на следующий фрагмент кода:

 .half-red { color: rgba(red, .5); } .message-error { color: red; @extend .half-red; } 

Если не считать имя семантического класса, это прекрасно код, верно? Вы, вероятно, ожидаете что-то вроде следующего при компиляции:

 /* This will not be the correct output! */ .message-error { color: red; color: rgba(255, 0, 0, 0.5); } 

Это выглядит как простой способ обеспечить постепенную деградацию для старых браузеров, которые не поддерживают rgba() цвета rgba() (мы не будем @extend на причинах использования @extend здесь; это не имеет значения). Но это не то, как будет выглядеть вывод CSS. Наоборот, это будет выглядеть так:

 .half-red, .message-error { color: rgba(255, 0, 0, 0.5); } .message-error { color: red; } 

Но почему?! Вы, вероятно, говорите, к несчастью. Это связано с тем, что директива @extend работает в обратном порядке. Из документации Sass :

@extend работает путем вставки расширяющего селектора […] в любое место таблицы стилей, где появляется расширенный селектор […].

В нашем примере «расширяющий селектор» — это .message-error а «расширенный селектор» — .half-red .

Опционально расширяется

В зависимости от типа приложения, над которым вы работаете, вы можете использовать или не использовать сторонние фреймворки или виджеты на основе CSS. Если некоторые из них написаны на Sass, ничто не мешает вам расширять селекторы из этих файлов.

К сожалению, если отсутствует расширенный селектор, Sass выдаст ошибку, и компиляция не удастся.

«.Message-error» не удалось @extend «.important».
Селектор «.important» не найден.
Используйте «@extend .important! Необязательный», если расширение может потерпеть неудачу.

Как вы можете видеть, вы можете передать !optional флаг !optional Вашим импортам, чтобы предотвратить их сбой, если расширенный селектор не найден. Это полезно также в случае, когда расширенный и расширенный селекторы конфликтуют:

 a.important { font-weight: bold; } p.message-error { @extend .important; } 

Действительно, это приводит к ошибке, поскольку оба селектора указаны, что делает невозможным их объединение. Таким образом, вы получите следующую ошибку:

Ни один селектор, соответствующий «.important», не может быть объединен с «p.message-error».

Добавление !optional флага !optional К вашему @extend решит эту проблему.

Расширение и медиа-запросы

Одна из самых больших проблем с @extend — отсутствие поддержки расширения внутри директивы @media . К сожалению, Sass не поддерживает кросс-медиа расширения:

 .important { font-weight: bold; } @media (max-width: 767px) { .message-error { @extend .important; } } 

Это приведет к следующей ошибке:

Вы не можете @ расширять внешний селектор из @media.
Вы можете использовать только @extend селекторы в пределах одной директивы.

Это связано с тем, что @extend в основном касается перемещения селекторов, а не правил CSS, как мы видели в разделе о сохранении порядка в исходном коде. Если Sass разрешил это, то расширение селектора, находящегося внутри другого медиа-запроса, приведет к чему-то вроде этого:

 .rule, @media(max-width: 767px) { .another-rule }, .another-another-rule { /* ... */ } 

… который, очевидно, не является действительным CSS.

При этом разработчики Sass хорошо осведомлены об этой проблеме (о чем свидетельствует возмутительное количество проблем, упоминающих об этом в своем репо: # 501 , # 640 , # 915 , # 1050 , # 1083 ).

Так как это является существенным недостатком продвинутой архитектуры Sass, они, скорее всего, скоро решат эту проблему. Согласно этому комментарию от Nex3 (ведущий разработчик Sass), это будет смешанная интерполяция .

Лучшие практики для @extend

Подводя итог, вот что я бы назвал лучшими практиками при использовании директивы @extend в Sass:

  • Убедитесь, что расширенный селектор присутствует только один раз в таблице стилей.
  • Избегайте расширения от вложенных селекторов.
  • Избегайте цепочек директив @extend .
  • Не пытайтесь расширяться из медиа-запроса; это не работает

Это завершает обсуждение @extend . Если вам есть что добавить, дайте мне знать в комментариях!

Эта статья была переведена на французский Пьером Шоффе для La Cascade