Наследование в SASS
В этой статье объясняется наследование в SASS.
Мы объясним наследование в SASS на практических примерах.
YouTube Video
Наследование в SASS
Наследование в SASS (@extend) — это механизм, который позволяет применять стили одного селектора к другому без дублирования. Поскольку одни и те же стили 'объединяются' и выводятся для нескольких элементов в разметке, итоговый CSS становится менее избыточным; однако неправильное использование может привести к неожиданному объединению селекторов.
Основы: как использовать @extend
Ниже приведён базовый пример, где .btn--primary наследует стили .btn. @extend — это директива, расширяющая целевой селектор.
1// Base button styles
2.btn {
3 padding: 0.5rem 1rem;
4 border-radius: 4px;
5 border: 1px solid #ccc;
6 background: white;
7 color: #333;
8}
9
10/* Primary button extends the base .btn */
11.btn--primary {
12 @extend .btn;
13 background: #007bff;
14 color: white;
15}- С помощью
@extend,.btn--primaryнаследует базовые стили от.btnи переопределяет только необходимые части.
Сгенерированный CSS
1.btn, .btn--primary {
2 padding: 0.5rem 1rem;
3 border-radius: 4px;
4 border: 1px solid #ccc;
5 background: white;
6 color: #333;
7}
8
9.btn--primary {
10 background: #007bff;
11 color: white;
12}Рекомендуемая практика: использование плейсхолдеров (%placeholder)
Селекторы-заполнители (%name) — это селекторы, которые не выводятся в CSS. Они широко используются, особенно когда вы хотите безопасно разделять общие стили исключительно для наследования между несколькими компонентами.
1// %placeholder will not be output directly
2%card-base {
3 padding: 1rem;
4 border-radius: 6px;
5 box-shadow: 0 1px 3px rgba(0,0,0,0.08);
6 background: #fff;
7}
8
9/* Components extend the placeholder */
10.card {
11 @extend %card-base;
12 border: 1px solid #eee;
13}
14
15.panel {
16 @extend %card-base;
17 border: 1px solid #ddd;
18}.cardи.panelоба наследуют от%card-base, что позволяет им разделять общие стили и при необходимости добавлять различия.
Сгенерированный CSS
1.card, .panel {
2 padding: 1rem;
3 border-radius: 6px;
4 box-shadow: 0 1px 3px rgba(0,0,0,0.08);
5 background: #fff;
6}
7
8.card {
9 border: 1px solid #eee;
10}
11
12.panel {
13 border: 1px solid #ddd;
14}Множественное наследование (несколько @extend)
Можно наследовать несколько плейсхолдеров или классов одновременно. Хотя повторное использование стилей улучшается, важно отслеживать, какие правила с какими селекторами комбинируются.
1%btn-base {
2 display: inline-block;
3 padding: 0.5rem 1rem;
4 border-radius: 3px;
5}
6
7%btn-large {
8 padding: 0.75rem 1.5rem;
9 font-size: 1.125rem;
10}
11
12/* Composite button that extends both placeholders */
13.btn--lg {
14 @extend %btn-base;
15 @extend %btn-large;
16 background: #222;
17 color: #fff;
18}- Это пример, где кнопка наследует два плейсхолдера: один для 'базового' стиля, другой для 'размера'.
.btn--lgнаследует как%btn-base, так и%btn-large, объединяя базовую компоновку с увеличенным размером.
Сгенерированный CSS
1.btn--lg {
2 display: inline-block;
3 /* %btn-large overrides the padding from %btn-base */
4 padding: 0.75rem 1.5rem;
5 border-radius: 3px;
6 font-size: 1.125rem;
7 background: #222;
8 color: #fff;
9}Особенности работы @extend (механизм объединения) и предостережения о 'взрыве селекторов'
@extend объединяет все совпадающие селекторы, что иногда может приводить к нежелательным комбинациям селекторов.
Следующий пример показывает, как может вырастать вывод CSS, если один и тот же базовый класс расширяется в нескольких местах.
1/* Many components extend .utility */
2/* A generic utility class */
3.utility {
4 margin-bottom: 1rem;
5}
6
7/* Nested selectors that extend .utility */
8.header {
9 @extend .utility;
10 .title {
11 font-weight: bold;
12 }
13}
14
15.footer {
16 @extend .utility;
17 .note {
18 color: #888;
19 }
20}
21
22.article {
23 @extend .utility;
24 .content {
25 line-height: 1.6;
26 }
27}
28
29.sidebar {
30 @extend .utility;
31 .section {
32 padding: 1rem;
33 }
34}- Когда несколько компонентов наследуют
.utility, селекторы объединяются в один, и в крупных проектах это может привести к раздутию CSS.
Сгенерированный CSS
1.utility,
2.header,
3.footer,
4.article,
5.sidebar {
6 margin-bottom: 1rem;
7}
8
9.header .title {
10 font-weight: bold;
11}
12
13.footer .note {
14 color: #888;
15}
16
17.article .content {
18 line-height: 1.6;
19}
20
21.sidebar .section {
22 padding: 1rem;
23}@extend и расширение .class vs элементные селекторы (теги) — приоритет и побочные эффекты
@extend можно применять не только к классам, но и к селекторам элементов. Однако расширение элементов увеличивает охват действия, что повышает риск непреднамеренного применения правил в нежелательных местах.
Ниже приведён пример расширения селектора элемента и его возможных последствий.
1/* Extending an element selector (not recommended) */
2h1 {
3 font-size: 2rem;
4 margin-bottom: 0.5rem;
5}
6
7/* If you extend h1, the resulting selector will include your class with h1 */
8.title {
9 @extend h1;
10 color: #333;
11}
12
13/* Output becomes:
14h1, .title { font-size: 2rem; margin-bottom: 0.5rem; }
15*/- В этом примере наследование селектора элемента
h1приводит к тому, что.titleобъединяется с теми же стилями, что иh1. - Хотя это может показаться удобным для небольших проектов, с ростом вашего проекта правила для
h1могут неожиданно комбинироваться с.title, что усложняет стили и снижает удобство поддержки. Поэтому создание стилей, в первую очередь, на основе классов и заполнителей делает их проще в поддержке.
Сгенерированный CSS
1h1,
2.title {
3 font-size: 2rem;
4 margin-bottom: 0.5rem;
5}
6
7.title {
8 color: #333;
9}Примеры использования @extend и !optional
Если указать !optional с @extend, можно подавлять ошибки, когда целевой объект наследования отсутствует. Это особенно полезно в коде, похожем на библиотеку, или в случаях, когда заполнители определяются условно.
Приведен пример безопасного попытки унаследовать класс, который может не существовать, с использованием !optional.
1/* Try to extend a class that might not exist */
2.component {
3 @extend .maybe-existing !optional;
4 padding: 1rem;
5}- Если
.maybe-existingне существует, ничего не произойдет — правило будет пропущено. Это можно использовать, когда необходимо безопасно попытаться расширить селектор.
Сгенерированный CSS
1.component {
2 padding: 1rem;
3}Сравнение @extend и миксинов (@mixin / @include)
@extend и @mixin иногда пересекаются по назначению, но их результаты и сценарии использования различаются.
-
@extend- Сгенерированный CSS снижает избыточность за счет объединения селекторов.
- Поскольку селекторы объединяются после генерации, могут возникать непредвиденные комбинации.
- Параметры передавать невозможно (однако это можно компенсировать комбинированием плейсхолдеров).
-
@mixin/@include- Каждый вызов дублирует стили (что приводит к избыточному выводу).
- Можно передавать параметры и включать логику, такую как условия или циклы.
- Вывод становится более предсказуемым, но размер файла увеличивается.
Ниже приведено сравнение использования @mixin и @extend для реализации одних и тех же стилей кнопки.
1/* Mixin approach */
2@mixin btn-styles($bg, $color) {
3 display: inline-block;
4 padding: 0.5rem 1rem;
5 background: $bg;
6 color: $color;
7 border-radius: 4px;
8}
9
10/* Use mixin */
11.btn {
12 @include btn-styles(white, #333);
13}
14
15.btn--primary {
16 @include btn-styles(#007bff, white);
17}
18
19/* Extend approach (shared placeholder) */
20%btn-base {
21 display: inline-block;
22 padding: 0.5rem 1rem;
23 border-radius: 4px;
24}
25
26.btn2 {
27 @extend %btn-base;
28 background: white;
29 color: #333;
30}
31
32.btn2--primary {
33 @extend %btn-base;
34 background: #007bff;
35 color: white;
36}@mixinпозволяет гибко добавлять стили, а@extendэффективно объединяет вывод, поэтому вы можете использовать каждый из подходов в зависимости от задачи.
Сгенерированный CSS
Вывод из @mixin
1.btn {
2 display: inline-block;
3 padding: 0.5rem 1rem;
4 background: white;
5 color: #333;
6 border-radius: 4px;
7}
8
9.btn--primary {
10 display: inline-block;
11 padding: 0.5rem 1rem;
12 background: #007bff;
13 color: white;
14 border-radius: 4px;
15}Вывод из @extend
1.btn2,
2.btn2--primary {
3 display: inline-block;
4 padding: 0.5rem 1rem;
5 border-radius: 4px;
6}
7
8.btn2 {
9 background: white;
10 color: #333;
11}
12
13.btn2--primary {
14 background: #007bff;
15 color: white;
16}Практические рекомендации
Наследование в SASS — это мощная возможность для повышения повторного использования стилей. Однако неправильное применение может усложнить объединение стилей и снизить поддерживаемость. Ниже приведены основные моменты для безопасного и эффективного использования наследования.
- Используйте заполнители для чисто общих стилей компонентов, таких как структура и расположение. Кроме того, если требуется динамическая параметризация, вы можете использовать
@mixin. - Следует избегать прямого наследования элементов HTML, таких как
h1. Могут возникать непреднамеренные комбинации селекторов, что может привести к неожиданному генерированию CSS. - Использование соглашений наименования, например BEM, или явных префиксов к плейсхолдерам помогает повысить безопасность кода.
- Безопаснее использовать
@extendв пределах одного файла. Особенно в крупных проектах рекомендуется проектировать наследование в рамках каждого компонента, чтобы облегчить отслеживание связей наследования.
Резюме
Функция @extend в SASS — это удобный способ эффективно повторно использовать общие стили и обеспечивать согласованность дизайна. Однако, поскольку комбинации селекторов могут легко усложняться, использовать эту функцию следует аккуратно и в ограниченном объеме. Группируя общие стили с помощью селекторов-заполнителей (%placeholder) и используя @mixin для частей, которые требуют динамических параметров, вы сможете поддерживать простой и удобный для обслуживания дизайн.
Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.