Как подключить стили, специфичные для компонента?

В Vue компонентах можно подключать стили, специфичные только для конкретного компонента, используя различные подходы. Самый распространённый и рекомендуемый способ — это использовать тег <style scoped>, но также возможны более гибкие и продвинутые методы, включая CSS-модули, динамическое подключение классов, использование препроцессоров (SCSS, LESS), а также подключение стилей через JavaScript или инъекцию глобальных стилей только для определённого компонента.

Использование <style scoped>

Когда ты добавляешь в .vue файл блок <style scoped>, Vue автоматически модифицирует селекторы CSS так, чтобы они применялись только к текущему компоненту. Это делается путём добавления уникального data-атрибута ко всем элементам в шаблоне и селекторам.

Пример:

&lt;template&gt;
&lt;div class="card"&gt;
&lt;h2&gt;Заголовок&lt;/h2&gt;
&lt;p&gt;Описание&lt;/p&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;style scoped&gt;
.card {
border: 1px solid #ccc;
padding: 1rem;
border-radius: 5px;
}
.card h2 {
color: teal;
}
&lt;/style&gt;

В скомпилированном HTML Vue добавит специальный атрибут (например, data-v-123abc) ко всем DOM-элементам в этом компоненте и CSS-селекторам:

&lt;div class="card" data-v-123abc&gt;
&lt;h2 data-v-123abc&gt;Заголовок&lt;/h2&gt;
&lt;p data-v-123abc&gt;Описание&lt;/p&gt;
&lt;/div&gt;

А CSS будет выглядеть так:

.card\[data-v-123abc\] {
...
}
.card h2\[data-v-123abc\] {
...
}

Это гарантирует, что стили применяются только к этому компоненту.

Особенности и ограничения scoped

  1. Селекторы не проникают в дочерние компоненты. Если хочешь стилизовать что-то внутри слота или дочернего компонента, scoped не поможет — потребуется использовать глубокие селекторы (::v-deep).

  2. Нельзя использовать глобальные теги напрямую. Например, стили для body, html, button и других глобальных элементов внутри <style scoped> будут ограничены текущим компонентом и, скорее всего, не подействуют, как ты ожидаешь.

Глубокая вложенность: ::v-deep

Если нужно применить стили к дочернему компоненту или элементу внутри слота, используется специальный селектор ::v-deep.

Пример:

&lt;style scoped&gt;
::v-deep .child-element {
color: red;
}
&lt;/style&gt;

Можно использовать также короткую запись:

&lt;style scoped&gt;
:deep(.child-element) {
color: red;
}
&lt;/style&gt;

Это позволяет обойти ограничение изоляции.

Использование CSS-модулей (в Vue CLI и Vite)

Если проект поддерживает CSS-модули, можно использовать их с module атрибутом:

&lt;template&gt;
&lt;div :class="$style.wrapper"&gt;Пример&lt;/div&gt;
&lt;/template&gt;
&lt;style module&gt;
.wrapper {
background-color: #f9f9f9;
padding: 10px;
}
&lt;/style&gt;

Vue автоматически преобразует классы в уникальные имена и даёт к ним доступ через объект $style.

Результат:

HTML: &lt;div class="wrapper_xyz123"&gt;  
CSS: .wrapper_xyz123 { ... }

Использование препроцессоров (scss, less, stylus)

Vue поддерживает препроцессоры из коробки, если проект настроен соответствующим образом (например, в vue-cli, vite или Nuxt).

&lt;style scoped lang="scss"&gt;
.card {
border: 1px solid #ccc;
padding: 1rem;
h2 {
color: orange;
}
}
&lt;/style&gt;

Чтобы это работало, должен быть установлен препроцессор (например, sass и sass-loader).

Динамическое применение стилей через привязку классов и стилей

Вместо описания в <style> можно динамически управлять классами и стилями из JavaScript части:

&lt;template&gt;
&lt;div :class="{ active: isActive }" :style="{ color: textColor }"&gt;Привет&lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
export default {
data() {
return {
isActive: true,
textColor: 'blue'
}
}
}
&lt;/script&gt;
&lt;style scoped&gt;
.active {
font-weight: bold;
}
&lt;/style&gt;

Подключение внешних CSS-файлов только для компонента

Так делать не всегда удобно, но можно импортировать стили прямо в <script>:

&lt;script&gt;
import './MyComponent.css';
export default {
// компонент
}
&lt;/script&gt;

Если этот импорт сделать только в компоненте, стили применятся только тогда, когда компонент будет загружен, но они всё равно попадут в общий CSS-бандл, если сборка не разделяет чанки.

Использование Vue composables и динамической инъекции стилей

Стили можно программно вставлять через JavaScript. Это более редкий приём, чаще используется в библиотеках.

const style = document.createElement('style');

style.innerText = \`.my-special-class { background: pink; }\`;

document.head.appendChild(style);

Такой подход используется, например, в библиотеках, когда компонент подключается динамически и должен вставить CSS вместе с собой.

Использование <style scoped lang="postcss">

Если ты используешь PostCSS или Tailwind CSS, можно включить конфигурацию через lang="postcss" или просто использовать utility-классы Tailwind, не подключая стили вручную.

Адаптация под SSR и Hydration

При серверном рендеринге (SSR) Vue корректно обрабатывает scoped-стили и изоляцию. Однако при использовании кастомных решений важно убедиться, что стили синхронизируются на клиенте и сервере.

Уникальные классы руками

Иногда разработчики создают уникальные классы вручную и применяют их только в нужных компонентах, как альтернатива scoped:

&lt;template&gt;
&lt;div class="my-comp-123-box"&gt;
...
&lt;/div&gt;
&lt;/template&gt;
&lt;style&gt;
.my-comp-123-box {
...
}
&lt;/style&gt;

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

Vue предоставляет мощные возможности для изоляции стилей, и большинство задач удобно решается с помощью scoped, v-deep и/или CSS Modules. Эти подходы позволяют писать переиспользуемые, масштабируемые и визуально независимые компоненты, не создавая конфликтов в глобальном пространстве стилей.