@extend
При разработке страницы часто возникают случаи, когда один класс должен иметь все стили другого класса, а также свои собственные специфические стили. Например, методология БЭМ поощряет классы-модификаторы, которые относятся к тем же элементам, что и классы блоков или элементов. Но это может создать загроможденный HTML, склонный к ошибкам из-за того, что забыли включить оба класса, и может внести несемантические проблемы стиля в вашу разметку.
<div class="error error--serious">
Oh no! You've been hacked!
</div>
.error {
border: 1px #f00;
background-color: #fdd;
}
.error--serious {
border-width: 3px;
}
Правило Sass @extend
решает эту проблему. Он написан @extend <selector>
и сообщает Sass, что один селектор должен наследовать стили другого.
Когда один класс расширяет другой, Sass стилизует все элементы, которые соответствуют расширителю, как если бы они также соответствовали расширяемому классу. Когда один селектор класса расширяет другой, он работает точно так же, как если бы вы добавили расширенный класс к каждому элементу в вашем HTML, который уже имел расширяющийся класс. Вы можете просто написать class="error--serious"
, и Sass позаботится о том, чтобы он был оформлен так, как если бы он также имел class="error"
.
Конечно, селекторы используются не только сами по себе в правилах стиля. Sass знает, что нужно расширять везде, где используется селектор. Это гарантирует, что ваши элементы будут стилизованы точно так, как если бы они соответствовали расширенному селектору.
⚠️ Внимание!
Расширения разрешаются после компиляции остальной части вашей таблицы стилей. В частности, это происходит после разрешения родительских селекторов. Это означает, что если вы используете @extend .error
, это не повлияет на внутренний селектор в .error { &__icon { ... } }
. Это также означает, что родительские селекторы в SassScript не могут видеть результаты расширения.
Как это работает permalinkКак это работает
В отличие от миксин, которые копируют стили в текущее правило стиля, @extend
обновляет правила стиля, содержащие расширенный селектор, так что они также содержат расширяющий селектор. При расширении селекторов Sass выполняет интеллектуальную унификацию:
Он никогда не генерирует селекторы вроде
#main#footer
, которые не могут соответствовать никаким элементам.Это гарантирует, что сложные селекторы чередуются, так что они работают независимо от того, в каком порядке вложены элементы HTML.
Он максимально сокращает избыточные селекторы, при этом гарантируя, что специфичность больше или равна специфичности расширителя.
Он знает, когда один селектор совпадает со всем, что делает другой, и может комбинировать их вместе.
Он разумно обрабатывает комбинаторы, универсальные селекторы и псевдоклассы, содержащие селекторы.
💡 Интересный факт:
Вы можете напрямую получить доступ к интеллектуальной унификации Sass, используя функции выбора! Функция selector.unify()
возвращает селектор, который соответствует пересечению двух селекторов, в то время как функция selector.extend()
работает так же, как @extend
, но с одним селектором.
⚠️ Внимание!
Поскольку @extend
обновляет правила стиля, которые содержат расширенный селектор, их стили имеют приоритет в каскаде в зависимости от того, где появляются правила стиля расширенного селектора, а не в зависимости от того, где появляется @extend
. Это может сбивать с толку, но помните: это тот же приоритет, который имели бы эти правила, если бы вы добавили расширенный класс в свой HTML!
Селекторы заполнителей permalinkСелекторы заполнителей
Иногда вы хотите написать правило стиля, которое только предназначено для расширения. В этом случае вы можете использовать селекторы-заполнители, которые выглядят как селекторы классов, начинающиеся с %
вместо .
. Любые селекторы, которые включают заполнители, не включаются в вывод CSS, но расширяют их.
Частные заполнители permalinkЧастные заполнители
Как и участники модуля, селектор-заполнитель можно пометить как частный, начав его имя с -
или _
. Селектор частного заполнителя может быть расширен только внутри таблицы стилей, которая его определяет. Для любых других таблиц стилей это будет выглядеть так, как будто этого селектора не существует.
Область расширения permalinkОбласть расширения
Когда одна таблица стилей расширяет селектор, это расширение будет влиять только на правила стиля, написанные в восходящих модулях, то есть на модули, которые загружаются этой таблицей стилей с помощью правила @use
или правилоа @forward
, модули, загруженные этими модулями, и так далее. Это помогает сделать ваши правила @extend
более предсказуемыми, гарантируя, что они влияют только на стили, о которых вы знали, когда их писали.
⚠️ Внимание!
Расширения вообще не имеют области видимости, если вы используете правило @import
. Они не только повлияют на каждую импортируемую вами таблицу стилей, но и повлияют на каждую таблицу стилей, которая импортирует вашу таблицу стилей, все остальное, что эти таблицы стилей импортируют, и так далее. Без @use
, расширения будут глобальными.
Обязательные и необязательные расширения permalinkОбязательные и необязательные расширения
Обычно, если @extend
не соответствует ни одному селектору в таблице стилей, Sass выдаст ошибку. Это помогает защитить от опечаток или переименования селектора без переименования селекторов, которые от него наследуются. Расширения, требующие наличия расширенного селектора, являются обязательными.
Однако это не всегда может быть тем, что вам нужно. Если вы хотите, чтобы @extend
не выполнял никаких действий, если расширенный селектор не существует, просто добавьте в конец !optional
.
Расширения или Миксины? permalinkРасширения или Миксины?
Расширения и примеси - это способы инкапсуляции и повторного использования стилей в Sass, что, естественно, поднимает вопрос о том, когда какой из них использовать. Миксины, очевидно, необходимы, когда вам нужно настроить стили с помощью аргументов, но что, если они всего лишь фрагменты стилей?
Как показывает опыт, расширения - лучший вариант, когда вы выражаете отношения между семантическими классами (или другими семантическими селекторами). Поскольку элемент с классом .error--serious
является ошибкой, для него имеет смысл расширить .error
. Но для несемантических коллекций стилей написание миксина может избежать каскадных головных болей и упростить настройку в дальнейшем.
💡 Интересный факт:
Большинство веб-серверов сжимают обслуживаемый ими CSS, используя алгоритм, который очень хорошо обрабатывает повторяющиеся фрагменты идентичного текста. Это означает, что, хотя миксины могут создавать больше CSS, чем расширять, они, вероятно, не существенно увеличат объем, необходимый вашим пользователям для загрузки. Так что выбирайте ту функцию, которая больше всего подходит для вашего варианта использования, а не ту, которая генерирует меньше всего CSS!
Ограничения permalinkОграничения
Запрещенные селекторы permalinkЗапрещенные селекторы
- Dart Sass
- ✓
- LibSass
- ✗
- Ruby Sass
- ✗
Только простые селекторы - отдельные селекторы, такие как .info
или a
могут быть расширены. Если бы .message.info
мог быть расширен, определение @extend
говорит, что элементы, соответствующие расширителю, будут иметь такой стиль, как если бы они соответствовали .message.info
. Это то же самое, что и сопоставление .message
и .info
, поэтому писать это вместо @extend .message, .info
не принесет никакой пользы.
Точно так же, если бы .main .info
можно было расширить, он бы делал (почти) то же самое, что и расширение .info
самостоятельно. Тонкие различия не стоят того, чтобы выглядеть так, будто он делает что-то существенно другое, так что это тоже недопустимо.
HTML-эвристика permalinkHTML-эвристика
Когда @extend
чередует сложные селекторы, он не генерирует все возможные комбинации селекторов предков. Многие из селекторов, которые он мог бы сгенерировать, вряд ли действительно будут соответствовать реальному HTML, и создание их всех сделало бы таблицы стилей слишком большими для очень небольшой реальной ценности. Вместо этого он использует эвристику: он предполагает, что предки каждого селектора будут самодостаточными, без чередования с предками других селекторов.
Расширить в @media permalinkРасширить в @media
Хотя @extend
разрешен в @media
и других at-правилах CSS, не разрешено расширять селекторы, которые появляются вне его at-правила. Это связано с тем, что расширяемый селектор применяется только в пределах данного медиа-контекста, и нет способа убедиться, что ограничение сохраняется в сгенерированном селекторе без дублирования всего правила стиля.