Перейти к содержанию

Отказ от scoped стилей в Vue

При работе с Vue многие привычно используют <style scoped>, ограничивая стили текущим компонентом. Разберёмся, действительно ли это нужно, или стало устаревшей привычкой, от которой можно отказаться.

scoped в Vue

<style scoped> добавляет каждому селектору уникальный атрибут вроде data-v-xxxx.

vue
<template>
  <button class="button">
    Click
  </button>
</template>
<style scoped>
.button { color: red; }
</style>

Компилируется в:

css
.button[data-v-1234] { color: red; }
  • Плюсы: полная изоляция стилей, отсутствие коллизий. Такие стили легко переносить между проектами и вы не рискуете случайно задеть существующие.
  • Минусы: небольшой runtime/compile overhead, раздувание CSS из-за добавленных хешей.

Scoped удобен для быстрых прототипов, но для крупных проектов это чаще лишняя нагрузка.

module в Vue

Vue поддерживает ещё один способ изоляции — CSS Modules, через <style module>.

vue
<template>
  <button :class="$style.button">
    Click
  </button>
</template>
<style module>
.button { color: red; }
</style>

Классы получают уникальные имена при компиляции (например button_abc123) и доступ через объект $style.

  • Плюсы: полная изоляция, удобно для динамических классов, можно комбинировать с BEM.
  • Минусы: синтаксис чуть сложнее ($style вместо обычного класса), больше boilerplate, не так нагляден для людей привыкших к plain CSS.

Если BEM уже соблюдается, CSS Modules чаще всего не нужны, но для компонентов с динамическими классами могут быть полезны.

Уникальные имена классов (BEM)

Если проект использует строгий нейминг, например BEM (Block-Element-Modifier), scoped можно не применять. Классы блоков уже уникальные, а дочерние элементы и модификаторы ограничены областью блока:

vue
<style>
.block {
  display: flex;
  flex-direction: column;
  &__element {
    flex-basis: 50%;
  }
  &--modifier {
    flex-direction: row;
  }
}
</style>
  • Плюсы: plain CSS без data-v-xxxx, уменьшенный размер бандла, отсутствие runtime/compile overhead. Отсутствие коллизий при строгом следовании BEM.
  • Минусы: требуется соблюдать BEM нейминг, который не всем по вкусу, незначительное увеличение времени на code review.

Этот вариант подходит для команд с code review и зафиксированными стандартами разработки.

Валидация классов и стилей

Соблюдение этих правил можно автоматизировать с помощью линтеров.

  • Stylelint — запрет не-BEM классов:
json
{
  "selector-class-pattern": "[a-z]([a-z-]+)?(__([a-z]+-?)+)?(--([a-z]+-?)+){0,2}"
}
  • Eslint — запрет scoped в <style> Vue-компонентов:
json
{
  "vue/enforce-style-attribute": ["error", { "allow": ["plain"] }]
}

Заключение

  • Scoped стилей можно смело избегать, если применяется строгий BEM.
  • CSS без scoped уменьшает размер бандла и нагрузку на runtime.
  • Линтеры stylelint и eslint помогут ускорить миграцию и предотвратить ошибки в будущем.
  • Scoped остаётся безопасным и допустимым подходом, но только если понимать цену его использования.