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

Работа со стилями и CSS в Vue js для красивых интерфейсов

Автор

Олег Марков

Введение

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

Организация CSS в проектах на Vue.js

Особенности CSS в Vue

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

Три способа применения CSS в компонентах

1. Частные стили в <style> внутри компонентов

Один из самых частых подходов — помещать стили прямо в файл компонента. Давайте посмотрим базовую структуру такого файла:

<template>
  <div class="hello">
    Привет, Vue!
  </div>
</template>

<script>
export default {
  name: 'HelloComponent'
}
</script>

<style>
.hello {
  color: blue; /* Цвет текста делаем синим */
  font-size: 20px; /* Размер шрифта */
}
</style>

Этот способ делает стиль видимым во всей области действия компонента или (если не использовать scoped) и для вложенных компонентов.

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

Вы можете подключать глобальные (общие для всего проекта) стили, например, через основной файл приложения (обычно main.js или main.ts):

// Импортируем глобальный CSS-файл для всего приложения
import './assets/global.css'

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

3. Использование CSS-фреймворков и библиотек

Vue хорошо интегрируется с популярными CSS-фреймворками вроде Tailwind CSS, Bootstrap, Vuetify и другими. Позже я покажу, как подключить их к вашему проекту.

Scoped-стили: инкапсуляция CSS в компонентах

Как работают scoped-стили

Добавьте атрибут scoped к вашему блоку <style>, чтобы его стили применялись только к этому компоненту:

<template>
  <div class="message">
    Только этот текст станет красным!
  </div>
</template>

<style scoped>
.message {
  color: red; /* Красный цвет применяется только внутри этого компонента */
}
</style>

Что происходит на самом деле: Vue автоматически добавляет специальные атрибуты к элементам и селекторам в DOM, чтобы предотвратить «протекание» стилей из одного компонента в другой. Это удобно для изоляции интерфейса каждого блока.

Где можно столкнуться с проблемами

Однако стоит иметь в виду, что глобальные селекторы, такие как body или переопределения по тегам (например, для стандартных input), при использовании scoped попадут в shadow DOM компонента и не затронут элементы вне этого блока.

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

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

Vue позволяет динамически изменять классы на элементах с помощью объектного и массивного синтаксиса. Смотрите пример:

<template>
  <button
    :class="{ active: isActive, 'button-large': isLarge }"
    @click="isActive = !isActive"
  >
    Нажми меня!
  </button>
</template>

<script>
export default {
  data() {
    return {
      isActive: false, // Флаг состояния
      isLarge: true    // Размер кнопки
    }
  }
}
</script>

<style scoped>
.active {
  background-color: #28a745; /* Зеленый фон для активной */
  color: white;
}
.button-large {
  font-size: 2rem;
  padding: 12px 24px;
}
</style>

Здесь при клике по кнопке будет добавляться или удаляться класс active, а от значения isLarge — еще и класс button-large.

Можно использовать и массивы:

:class="['my-class', isActive ? 'active' : '']"

Динамические инлайн-стили

Также вы можете передавать стили в атрибут :style как объект или строку:

<template>
  <div :style="{ color: textColor, fontSize: fontSize + 'px' }">
    Динамический стиль текста
  </div>
</template>

<script>
export default {
  data() {
    return {
      textColor: '#e63946',
      fontSize: 18
    }
  }
}
</script>

С помощью вычисляемых свойств удобно делать сложные вычисления для стилей:

<template>
  <div :style="computedStyle">
    Стили вычисляются динамически!
  </div>
</template>

<script>
export default {
  data() {
    return {
      danger: true
    }
  },
  computed: {
    computedStyle() {
      return this.danger
        ? { color: 'red', fontWeight: 'bold' }
        : { color: 'black' }
    }
  }
}
</script>

Обратите внимание, что если вы хотите добавить несколько CSS-свойств, используйте объект (каждое свойство — отдельное ключ-значение).

CSS-препроцессоры в Vue: Sass, Less, Stylus

Vue поддерживает работу с CSS-препроцессорами прямо «из коробки» (во Vue CLI-проектах). Это значит, что вы можете писать стили с использованием переменных, вложенности и миксинов, например, через Sass или SCSS.

<style scoped lang="scss">
$main-color: #4f8ef7;

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

Для этого убедитесь, что соответствующие пакеты (например, sass или less) установлены в вашем проекте.

CSS-модули: Локальная область видимости классов

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

<template>
  <div :class="$style.wrapper">
    Контент с CSS-модулем
  </div>
</template>

<style module>
.wrapper {
  color: #444;
  padding: 20px;
  border-radius: 8px;
}
</style>

Примечание: теперь классы подключаются через $style.className, а не просто через class="wrapper".

Вы также можете использовать оба подхода — и обычные, и module-стили — в одном компоненте, если это необходимо.

Использование глобальных CSS-переменных и миксинов

Если вам нужно применять одни и те же значения цветов, отступов или других параметров в разных компонентах, рассмотрите использование CSS custom properties (переменных) или миксинов.

Контекстный пример с переменными:

:root {
  --main-color: #2196f3;
  --secondary-color: #f5f5f5;
}

В компоненте вы сможете использовать их так:

<template>
  <div class="banner">Welcome!</div>
</template>

<style scoped>
.banner {
  background: var(--main-color);
  color: var(--secondary-color);
}
</style>

Переменные можно переопределять для отдельных компонентов через :root или локально через дополнительный селектор.

Глобальные и локальные классы: best practices

Когда использовать глобальные, а когда локальные стили?

  • Глобальные стили — для базовых форматов (reset, normalize, общие переменные, шрифты).
  • Scoped-стили — для стилизации отдельных компонентов, чтобы не было конфликтов между классами в разных участках интерфейса.
  • CSS-модули — для компонентов, где важна уникальность классов и их отсутствие в глобальном пространстве имен.

Такой подход помогает держать проект чистым и понятным, особенно по мере его роста.

Интеграция с CSS-фреймворками и библиотеками

Пример с настройкой Tailwind CSS

Tailwind — это современный utility-first CSS-фреймворк, который отлично подходит для Vue. Смотрите как можно включить Tailwind в ваш проект:

  1. Установите Tailwind через npm:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
  1. Настройте tailwind.config.js и postcss.config.js (эти файлы появляются автоматически).
  2. Импортируйте Tailwind в ваш глобальный CSS:
@tailwind base;
@tailwind components;
@tailwind utilities;
  1. Используйте utility-классы Tailwind в ваших компонентах:
<template>
  <button class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded">
    Кнопка Tailwind
  </button>
</template>

Пример с Vuetify

Для создания material-интерфейсов можно использовать Vuetify:

  1. Установите пакет:
npm install vuetify
  1. Подключите Vuetify к вашему приложению (например, в main.js):
import { createApp } from 'vue';
import App from './App.vue';
import { createVuetify } from 'vuetify'
import 'vuetify/styles'

const vuetify = createVuetify();

createApp(App)
  .use(vuetify)
  .mount('#app')
  1. Используйте компоненты Vuetify и их классы:
<template>
  <v-btn color="primary">Кнопка Vuetify</v-btn>
</template>

Vuetify сам управляет стилями компонентов через встроенные классы.

Анимации и переходы: создание плавных эффектов

Vue предлагает удобные инструменты для анимации — директива <transition>. Вот базовый пример:

<template>
  <button @click="show = !show">Показать/Скрыть</button>
  <transition name="fade">
    <p v-if="show">Привет, я появляюсь с плавной анимацией!</p>
  </transition>
</template>

<script>
export default {
  data() {
    return {
      show: true
    }
  }
}
</script>

<style scoped>
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter-from, .fade-leave-to {
  opacity: 0;
}
</style>

Здесь задаются стили для классов анимации: при появлении и исчезновении элемент плавно меняет прозрачность.

Практический пример структурирования CSS в проекте

Давайте я покажу вам, как может быть структурирован проект реального приложения на Vue.

Структура файлов:

src/
├─ components/
│  ├─ Header.vue
│  ├─ UserCard.vue
├─ assets/
│  ├─ global.css
│  ├─ variables.scss
│  ├─ mixins.scss
  • В файле assets/global.css можно расположить normalize, стили для body, базовые цвета приложения.
  • В файле variables.scss — все SCSS-переменные для переиспользования (цвета, размеры и т.д.).
  • Каждый компонент (например, Header.vue) содержит свой scoped style с внутренними классами для уникальности.

Пример подключения SCSS-переменных:

// assets/variables.scss
$primary-color: #635dff;
$border-radius: 6px;
<style scoped lang="scss">
@import "@/assets/variables.scss";
.header {
  background: $primary-color;
  border-radius: $border-radius;
}
</style>

Заключение

Vue.js предоставляет разнообразные инструменты для стилизации ваших компонентов: от глобальных и локальных стилей до поддержки CSS-препроцессоров, CSS-модулей и популярных фреймворков. Вы можете комбинировать scoped-стили, динамические классы, а также использовать анимации и переменные для построения масштабируемых и стильных интерфейсов. Такой подход обеспечивает чистоту кода, его предсказуемость и предотвращает случайные конфликты между стилями из разных частей приложения. Благодаря высокой гибкости вы сможете строить как минималистичные интерфейсы, так и сложные дизайн-системы, не теряя удобства поддержки и расширения стилизаций в будущем.

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

Вопрос 1: Как добавить глобальные переменные SCSS, чтобы их видели все компоненты?

Чтобы SCSS-переменные были доступны в каждом компоненте без ручного импорта, настройте section "style-resources" в vue.config.js (если используете Vue CLI) или настройте глобальную загрузку переменных через webpack.config.js, используя плагин sass-resources-loader.

Вопрос 2: Почему scoped-стили не применяются к дочерним компонентам?

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

Вопрос 3: Как переопределить стили сторонней библиотеки для отдельных компонентов?

Добавляйте override-стили в блоке <style scoped> в вашем компоненте, используя селектор ::v-deep или /deep/ для повышения специфичности. Например:

::v-deep .external-class {
  color: red;
}

Вопрос 4: Как удалить неиспользуемые CSS-стили из продакшн-сборки?

Используйте инструменты типа PurgeCSS (с Tailwind он идет в комплекте или через PostCSS), либо настройте webpack для удаления неиспользуемых стилей при финальной сборке.

Вопрос 5: Как динамически менять тему (light/dark) во Vue-приложении?

Реализуйте переключение темы через привязку переменных цветов к root-элементу и классам (например, через data-theme на body), а затем используйте эти переменные в SCSS/CSS. Переключение темы — это просто смена значения атрибута или класса и, следовательно, соответствующих переменных.

Стрелочка влевоСоздание и работа с дистрибутивом build dist Vue приложенийСоздание и структурирование Vue.js приложенияСтрелочка вправо

Постройте личный план изучения Vue до уровня Middle — бесплатно!

Vue — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по 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Применение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в 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
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Vue 3 и Pinia

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий