Наследование в SASS

Наследование в 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-канал.

YouTube Video