Scoped стили в компонентах

Vue.js предоставляет мощный механизм для создания компонентов с инкапсулированной структурой и стилями. Одной из ключевых особенностей является возможность использования scoped стилей, позволяющих применять CSS только к текущему компоненту без риска затрагивания глобальных элементов страницы или других компонентов.


Основы использования scoped

В компонентах Vue стили объявляются внутри <style> с атрибутом scoped:

<template>
  <div class="card">
    <h2 class="title">Заголовок</h2>
    <p class="description">Описание компонента</p>
  </div>
</template>

<script>
export default {
  name: 'CardComponent'
};
</script>

<style scoped>
.card {
  border: 1px solid #ccc;
  padding: 16px;
  border-radius: 8px;
}
.title {
  font-size: 18px;
  color: #333;
}
.description {
  font-size: 14px;
  color: #666;
}
</style>

При использовании scoped Vue автоматически добавляет уникальные атрибуты к элементам DOM компонента и к соответствующим селекторам CSS. Например, <div class="card"> может получить атрибут data-v-123abc, а CSS будет сгенерирован как .card[data-v-123abc], что исключает влияние на другие компоненты.


Механизм работы

Scoped стили работают за счет компиляции CSS с атрибутами:

  1. Компонентные селекторы: все селекторы в scoped CSS получают уникальный атрибут.
  2. Изоляция стилей: стили применяются только к элементам с этим атрибутом.
  3. Поддержка вложенных селекторов: псевдоклассы и дочерние элементы тоже получают атрибуты.

Пример с вложенными элементами:

<template>
  <div class="menu">
    <ul>
      <li>Пункт 1</li>
      <li>Пункт 2</li>
    </ul>
  </div>
</template>

<style scoped>
.menu ul {
  list-style: none;
  padding: 0;
}

.menu li {
  padding: 8px 0;
}
</style>

Каждый селектор .menu ul и .menu li будет сгенерирован с уникальным атрибутом, исключая конфликты с глобальными <ul> и <li>.


Scoped + глобальные стили

В некоторых случаях требуется смешивание scoped и глобальных правил. Для этого используется селектор ::v-deep или глобальный <style> без scoped.

Пример использования ::v-deep:

<template>
  <div class="container">
    <button class="btn">Нажми меня</button>
  </div>
</template>

<style scoped>
.container ::v-deep(.btn) {
  background-color: blue;
  color: white;
}
</style>

Селектор ::v-deep позволяет стилизовать глубоко вложенные компоненты или сторонние классы, игнорируя локальную изоляцию.


Ограничения и рекомендации

  1. Наследование селекторов: scoped не изолирует селекторы от глобальных тегов напрямую. Например, селектор body будет глобальным, даже если указан scoped.
  2. Модульные CSS: для более сложных случаев рекомендуется использовать CSS Modules вместе с Vue, чтобы управлять именами классов программно.
  3. Переопределение внешних библиотек: чтобы переопределить стили сторонних библиотек, необходимо использовать ::v-deep или глобальные селекторы.
  4. Производительность: scoped добавляет атрибуты к DOM, но современный рендеринг Vue делает это почти незаметным по производительности.

Применение с препроцессорами

Scoped стили отлично сочетаются с препроцессорами CSS, такими как SASS, LESS, Stylus. Атрибут scoped работает независимо от препроцессора.

<style lang="scss" scoped>
.card {
  border: 1px solid #ccc;
  padding: 16px;
  border-radius: 8px;

  .title {
    font-size: 18px;
    color: #333;
  }

  .description {
    font-size: 14px;
    color: #666;
  }
}
</style>

Синтаксис вложенных селекторов упрощает структуру и повышает читаемость кода.


Динамические классы и scoped

Scoped стили также прекрасно работают с динамическими классами через директиву :class:

<template>
  <div :class="['alert', type]">Сообщение</div>
</template>

<script>
export default {
  data() {
    return {
      type: 'success' // success, warning, error
    };
  }
};
</script>

<style scoped>
.alert {
  padding: 12px;
  border-radius: 4px;
}

.success {
  background-color: #dff0d8;
  color: #3c763d;
}

.warning {
  background-color: #fcf8e3;
  color: #8a6d3b;
}

.error {
  background-color: #f2dede;
  color: #a94442;
}
</style>

Vue автоматически связывает динамические классы с уникальными атрибутами scoped, что гарантирует локальность стилей для всех состояний.


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