логотип PurpleSchool
логотип PurpleSchool

Работа со стилями и стилизацией в Vue

Автор

Иван Сергеев

Введение

Стилизация пользовательского интерфейса — неотъемлемая часть фронтенд-разработки, и во Vue для этого предусмотрено множество удобных возможностей. Вы можете применять стандартные CSS-классы, использовать inline-стили, подключать глобальные таблицы стилей или создавать изолированное оформление для отдельных компонентов через scoped-стили. Помимо стандартных подходов, Vue предлагает реактивную и динамическую стилизацию, что отлично сочетается с компонентным подходом фреймворка.

Давайте разложим по полочкам, как во Vue работать со стилями, и рассмотрим самые частые сценарии для реальных проектов.

Стилизация компонентов во Vue: основные подходы

Базовые способы подключения стилей

Во Vue есть несколько основных способов стилизовать часть или весь проект:

  • Глобальные CSS-файлы (подключаются в корневой точке, например, main.js)
  • Локальные стили внутри .vue-компонента (через тег <style>)
  • Scoped-стили
  • Динамические классы и инлайн-стили
  • CSS-препроцессоры (Sass, Less и др.)
  • CSS-модули

Рассмотрим каждый подход на примерах.

Глобальные стили

Если вам нужно применить стили сразу ко всему приложению, это делается через отдельный CSS-файл. Например, создайте src/assets/styles/global.css и подключите его в точке входа:

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import './assets/styles/global.css' // Глобальные стили

createApp(App).mount('#app')

Все селекторы из этого файла будут действовать на все DOM-элементы приложения. Это удобно для базовых переменных, сброса стилей, типографики и других общих вещей.

Локальные и scoped стили

Обычные стили в компоненте

В каждом .vue-файле можно создать тег <style>, где можно разместить стили только для этого компонента:

<template>
  <button class="my-btn">Click me</button>
</template>

<style>
.my-btn {
  background: #337ab7;
  color: white;
  padding: 10px 20px;
  border-radius: 5px;
}
</style>

Однако такой стиль считается глобальным: если в каких-то других компонентах использовать класс my-btn, этот стиль отработает и там. Часто это не то, что нужно, и здесь пригодится scoped-стилизация.

Scoped стили: изоляция стилей

Добавив атрибут scoped к вашему стилю, вы получите изолированное пространство для CSS этого компонента:

<template>
  <button class="my-btn">Click me</button>
</template>

<style scoped>
.my-btn {
  background: #337ab7;
  color: white;
}
</style>

Vue реализует scoped-стилизацию с помощью атрибутов, которые автоматически добавляются к элементам и селекторам в скомпилированном коде, создавая уникальные идентификаторы. В результате, стили применяются только к элементам данного компонента.

Примечание: Scoped-стили не изолируют стили дочерних компонентов! Если вы стилизуете корневой тег компонента, дочерний компонент может не унаследовать ваш стиль, так как его структура изолирована.

Как работает scoped: быстрый разбор

Смотрите, как преобразуются стили при сборке:

<button class="my-btn" data-v-123abc>Click me</button>

а CSS превращается в

.my-btn[data-v-123abc] { /* стили */ }

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

Scoped-стили и глубокое воздействие

Иногда нужно пробросить стиль глубже в DOM, например, на дочерние компоненты. Для этого используются селекторы-deep.

В Vue 3 стандартным способом является ::v-deep:

<style scoped>
.button::v-deep .inner { color: red; }
</style>

Этот селектор позволит обратиться к элементу внутри дочернего компонента.

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

Один из главных плюсов Vue — поддержка реактивных свойств для классов и стилей.

:class — динамическое управление классами

С помощью директивы :class можно реагировать на изменения данных:

<template>
  <button :class="{ active: isActive }">Toggle</button>
</template>

<script setup>
import { ref } from 'vue'
const isActive = ref(false);
</script>

Этот код добавит класс active, если переменная isActive равна true.

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

<template>
  <div :class="['base-class', dynamicClass]"></div>
</template>

<script setup>
const dynamicClass = 'highlighted'; // Класс будет добавлен вместе с 'base-class'
</script>

Такой подход идеально подходит для управления разметкой через состояние.

:style — динамические inline-стили

Похожим образом работает директива :style, где значение может быть объектом или массивом объектов:

<template>
  <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
</template>

<script setup>
const activeColor = 'crimson'
const fontSize = 18
</script>

Или с реактивными данными:

<template>
  <div :style="styleObject"></div>
</template>

<script setup>
import { reactive } from 'vue'

const styleObject = reactive({
  backgroundColor: '#f5f5f5',
  border: '1px solid #ccc'
})
</script>

Это очень удобно при работе с темами, оформлением в зависимости от входных данных или выделением элементов.

Работа с CSS-переменными

Vue активно поддерживает использование CSS-переменных (var(--variable)). Вы можете задавать CSS-переменные локально в style, через пропсы, или даже динамически из кода:

<template>
  <div class="themed" :style="themeVars">Dynamic Theming</div>
</template>

<script setup>
import { computed } from 'vue'

const mainColor = 'teal'

const themeVars = computed(() => ({
  '--main-color': mainColor,
  '--padding': '12px'
}))
</script>

<style scoped>
.themed {
  color: var(--main-color);
  padding: var(--padding);
}
</style>

Такой способ идеально подходит, если вам нужно удобно управлять цветовыми схемами или делать runtime-перемены темы.

Использование препроцессоров (Sass, Less, Stylus)

Vue CLI и Vite отлично интегрируются с CSS-препроцессорами. Просто добавьте нужные пакеты (sass, less, stylus), и вы сможете писать компактный, вложенный и наглядный CSS прямо внутри <style lang="scss" scoped>:

<style lang="scss" scoped>
$main: #148;

.button {
  background: $main;
  &:hover {
    background: darken($main, 10%);
  }
}
</style>

Не забудьте установить препроцессор:

npm install -D sass

И используйте его в компонентах.

CSS-модули

Ещё один способ добиться изоляции — CSS-модули. Во Vue 3 они поддерживаются из коробки:

<template>
  <div :class="$style.title">CSS Modules Example</div>
</template>

<style module>
.title {
  color: royalblue;
  font-weight: bold;
}
</style>

Здесь вы обращаетесь к сгенерированному classname через $style.title, и такой стиль будет уникален для компонента.

Дополнительно, если используете шаблонизацию через <script setup>, импортируйте стили так:

<script setup>
defineProps(['$style'])
</script>

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

Глобальные и локальные стили в одном проекте

Практически всегда в больших проектах сочетаются:

  • глобальные стили для общих элементов
  • scoped-стили для переопределений внутри компонентов
  • динамические классы и инлайн-стили для живой реактивности

Это позволяет поддерживать архитектуру чистой и понятной.

Подключение сторонних CSS-фреймворков

Vue совместим с любыми CSS-фреймворками, такими как Bootstrap, Tailwind CSS, Bulma и др. Вы можете импортировать CSS-файл фреймворка в точке входа или использовать специальную обёртку для Vue:

// main.js
import 'bootstrap/dist/css/bootstrap.min.css'

Если вы используете Utility-first CSS-фреймворки вроде Tailwind, настройте его согласно официальной документации.

Стилизация через props

Иногда компоненты сами принимают данные для стилизации. Пример передачи стиля через пропсы:

<template>
  <button :style="{ background: color }">Custom Button</button>
</template>

<script setup>
defineProps({
  color: {
    type: String,
    default: '#389e0d'
  }
})
</script>

Теперь при использовании компонента вы можете явно указать цвет:

<CustomButton color="#ff9a00" />

Этот стиль напрямую попадёт в инлайновое свойство кнопки.

Scoped-стили и сторонние библиотеки

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

Ленивая загрузка стилей

Vue (особенно при работе с Vite или Webpack) умеет разбивать CSS по чанкам. Стили компонент с тегом <style scoped> или <style module> грузятся только если компонент реально требуется. Это уменьшает итоговый размер вашего bundle.

Лучшие практики оформления стилей в Vue

  • Использовать scoped-стили для компонентов по умолчанию
  • Хранить общие переменные/миксины/preflight-стили в глобальном CSS
  • Для тем или крупных переключений — использовать CSS-переменные
  • Стараться избегать глобальных селекторов типа div { ... } (за пределами глобального файла с преднамеренными сбросами)
  • Избегать излишнего усложнения селекторов; лучше делать короткие, ясные классы

Заключение

Стилизовать компоненты во Vue можно гибко и удобно: поддерживаются глобальные и локальные стили, есть поддержка препроцессоров, CSS-модулей и динамической стилизации любых элементов. Используйте scoped-стили для изоляции специфических селекторов, динамические директивы для реактивного оформления и глобальные таблицы стилей для фундаментальных настроек интерфейса. Благодаря множеству инструментов и best practices вы сможете поддерживать чистоту, масштабируемость и предсказуемость стилевой архитектуры вашего Vue-приложения.

Частозадаваемые технические вопросы по теме статьи и ответы на них

1. Почему стили с тегом <style scoped> не применяются к элементам, находящимся внутри дочерних компонентов?

Scoped-стили во Vue работают только в рамках текущего компонента. Если вы хотите пробросить стиль на глубоких потомков, используйте селектор ::v-deep:

/* Передавайте стиль внутренним элементам дочерних компонентов */
.parent ::v-deep .child-element {
  color: red;
}

2. Как можно динамически переключать темы (светлая/темная) во Vue на уровне приложения?

Сделайте корневой компонент с динамическими CSS-переменными и пробрасывайте их через директиву :style на корневой контейнер:

<template>
  <div :style="themeVars">
    <slot/>
  </div>
</template>

<script setup>
import { computed } from 'vue'
const darkTheme = true
const themeVars = computed(() => darkTheme ?
  { '--background': '#111', '--text': '#fff' }
  :
  { '--background': '#fff', '--text': '#222' }
)
</script>

Весь интерфейс внутри будет оформляться с помощью переменных.

3. Как добавить глобальные миксины в SCSS для использования во всех компонентах?

Создайте отдельный файл с миксинами/переменными и используйте настройку stylePreprocessorOptions (Vite) или vue.config.js (Vue CLI), чтобы автоматически импортировать его в каждый компонент.

// vite.config.js
css: {
  preprocessorOptions: {
    scss: {
      additionalData: `@import "@/assets/styles/mixins.scss";`
    }
  }
}

4. Есть ли способ сменить стили компонента в зависимости от родительского класса (например — для dark mode)?

Да, используйте глобальные (non-scoped) стили или CSS-переменные. Scoped-стили не учитывают родителей. Например:

.dark-mode .my-component {
  background: #222;
}

5. Почему при использовании CSS-модулей часть стилей перестает применяться к элементам, у которых класс задается напрямую через class=""?

Когда вы используете CSS-модули, стили применяются только к элементам, у которых класс динамически передан через свойство $style, например :class="$style.title". Если использовать просто class="title", класс будет обычным, без сгенерированного уникального имени, а соответственно и стили не применятся. Всегда используйте $style при работе с CSS-модулями.

Стрелочка влевоИспользование Swiper для создания слайдеров в VueСтруктура и особенности Single File Components SFC в VueСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueУправление пользователями и их данными в Vue приложенияхПрименение v-bind для динамической привязки атрибутов в VueСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний