Импорт CSS из JavaScript

Vite поддерживает импорт CSS-файлов непосредственно из JavaScript и TypeScript-модулей. Такой подход является стандартным механизмом работы со стилями в современной frontend-разработке. Вместо подключения <link> в HTML стили импортируются в точке входа приложения или внутри отдельных компонентов.

Простейший пример:

import './style.css'

После запуска dev-сервера Vite автоматически:

  • находит CSS-файл;
  • обрабатывает зависимости;
  • вставляет стили в страницу;
  • отслеживает изменения через HMR;
  • обновляет CSS без полной перезагрузки страницы.

Базовая структура проекта

Типичная структура:

project/
├── index.html
├── src/
│   ├── main.js
│   ├── style.css
│   └── components/
└── vite.config.js

Файл main.js:

import './style.css'

console.log('Vite app')

Файл style.css:

body {
    margin: 0;
    font-family: Arial, sans-serif;
}

Как Vite обрабатывает CSS

При импорте CSS Vite рассматривает файл как модуль зависимостей.

Процесс выглядит следующим образом:

  1. JavaScript импортирует CSS.
  2. Vite анализирует импорт.
  3. CSS проходит через внутренний pipeline.
  4. Dev Server внедряет стили в <style>.
  5. При сборке CSS извлекается в отдельные файлы.

Во время разработки стили подключаются динамически, а в production-сборке Vite формирует оптимизированные CSS-бандлы.


Импорт нескольких CSS-файлов

Можно импортировать любое количество файлов:

import './reset.css'
import './variables.css'
import './layout.css'
import './theme.css'

Порядок импортов имеет значение.

Если два файла содержат одинаковые правила:

.button {
    color: red;
}

и

.button {
    color: blue;
}

то применится стиль из файла, импортированного позже.


Импорт CSS внутри компонентов

Один из основных подходов — импортировать стили рядом с компонентом.

Структура:

src/
├── components/
│   ├── Button.js
│   └── Button.css

Button.js:

import './Button.css'

export function Button() {
    const button = document.createElement('button')

    button.className = 'button'
    button.textContent = 'Click'

    return button
}

Button.css:

.button {
    padding: 12px 18px;
    border-radius: 8px;
    background: royalblue;
    color: white;
}

Такой подход:

  • улучшает модульность;
  • упрощает поддержку;
  • уменьшает связанность файлов;
  • делает компонент самодостаточным.

Импорт CSS в TypeScript

Vite одинаково работает с JavaScript и TypeScript.

Пример:

import './style.css'

const app: HTMLElement | null = document.querySelector('#app')

if (app) {
    app.innerHTML = '<h1>Hello Vite</h1>'
}

Дополнительная настройка для обычного CSS не требуется.


Hot Module Replacement для CSS

Одно из ключевых преимуществ Vite — мгновенное обновление стилей.

При изменении CSS:

  • браузер не перезагружается;
  • DOM не пересоздаётся;
  • состояние приложения сохраняется;
  • обновляются только стили.

Например:

.card {
    background: white;
}

После изменения:

.card {
    background: black;
}

обновление происходит практически мгновенно.


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

Часто создаётся единый глобальный файл:

src/styles/global.css

Подключение:

import './styles/global.css'

Обычно туда помещают:

  • reset.css;
  • normalize.css;
  • CSS variables;
  • базовую типографику;
  • глобальные utility-классы;
  • настройки body/html.

Пример:

:root {
    --color-primary: #2563eb;
    --container-width: 1200px;
}

body {
    margin: 0;
    background: #f5f5f5;
}

Импорт CSS из npm-пакетов

Vite умеет импортировать стили из node_modules.

Пример:

import 'swiper/css'

или:

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

Vite автоматически найдёт пакет и подключит стили.


Импорт CSS вместе с библиотекой

Некоторые библиотеки требуют обязательного подключения CSS.

Пример со Swiper:

import Swiper from 'swiper'
import 'swiper/css'

Без CSS библиотека может работать некорректно:

  • отсутствуют размеры;
  • ломается layout;
  • пропадают анимации;
  • нарушается позиционирование.

Каскад и область видимости

Обычный CSS, импортированный в JavaScript, остаётся глобальным.

Пример:

h1 {
    color: red;
}

Такой стиль повлияет на все <h1> в приложении.

Это важно учитывать при построении архитектуры проекта.


Конфликты глобальных стилей

При большом количестве импортов возможны конфликты:

.container {
    width: 100%;
}

и:

.container {
    max-width: 1200px;
}

Для уменьшения конфликтов применяют:

  • CSS Modules;
  • BEM;
  • utility-first CSS;
  • namespace-подходы;
  • scoped CSS в фреймворках.

CSS Modules в Vite

Vite поддерживает CSS Modules из коробки.

Файл:

Button.module.css

Импорт:

import styles from './Button.module.css'

Использование:

button.className = styles.button

CSS:

.button {
    background: crimson;
}

Vite генерирует уникальные имена классов:

.button_a1b2c3

Это предотвращает пересечения стилей.


Разница между обычным CSS и CSS Modules

Обычный CSS

import './style.css'
  • глобальная область видимости;
  • классы доступны везде;
  • возможны конфликты.

CSS Modules

import styles from './style.module.css'
  • локальная область видимости;
  • автоматическая изоляция;
  • безопасные имена классов.

Импорт CSS в асинхронных модулях

При динамическом импорте JavaScript Vite автоматически подгружает связанные CSS-файлы.

Пример:

const module = await import('./dashboard.js')

Если dashboard.js содержит:

import './dashboard.css'

то Vite загрузит CSS только при необходимости.

Это особенно полезно для:

  • lazy loading;
  • code splitting;
  • SPA;
  • больших интерфейсов;
  • административных панелей.

CSS Code Splitting

Во время production-сборки Vite умеет разбивать CSS на чанки.

Например:

Home.js
Dashboard.js
Profile.js

Каждый модуль может иметь собственный CSS.

Vite создаст:

home.css
dashboard.css
profile.css

Это уменьшает объём первоначальной загрузки.


Автоматическое извлечение CSS при build

Во время vite build:

npm run build

Vite:

  • объединяет CSS;
  • минимизирует стили;
  • удаляет лишние пробелы;
  • оптимизирует порядок загрузки;
  • извлекает CSS в отдельные файлы.

Результат:

dist/assets/index-xxxxx.css

Использование PostCSS

Vite автоматически поддерживает PostCSS.

Можно установить плагины:

npm install postcss autoprefixer -D

Файл postcss.config.js:

export default {
    plugins: {
        autoprefixer: {}
    }
}

После этого любой импортируемый CSS будет проходить через PostCSS.


Использование Sass и SCSS

Vite поддерживает Sass.

Установка:

npm install sass -D

Импорт:

import './style.scss'

Файл:

$primary: royalblue;

body {
    background: $primary;
}

Импорт Less

Поддержка Less:

npm install less -D

Импорт:

import './theme.less'

Импорт Stylus

Поддержка Stylus:

npm install stylus -D

Импорт:

import './style.styl'

URL внутри CSS

Vite автоматически обрабатывает ресурсы внутри CSS.

Пример:

.logo {
    background-image: url('./images/logo.png');
}

Vite:

  • найдёт файл;
  • оптимизирует путь;
  • перенесёт ресурс в build;
  • создаст hashed filename.

Aliases для CSS-импортов

Если настроен alias:

resolve: {
    alias: {
        '@': '/src'
    }
}

можно писать:

import '@/styles/global.css'

Это особенно удобно в крупных проектах.


Импорт CSS в Vue

В Vue-компонентах Vite автоматически поддерживает стили:

<script setup>
import './button.css'
</script>

или:

<style>
.button {
    color: red;
}
</style>

Импорт CSS в React

React-проекты на Vite используют тот же механизм.

import './App.css'

export default function App() {
    return <h1>Hello</h1>
}

Tree Shaking и CSS

CSS не tree-shake’ится так же эффективно, как JavaScript.

Если импортирован файл:

import './huge-library.css'

то весь CSS обычно попадёт в сборку.

Для уменьшения размера применяются:

  • PurgeCSS;
  • Tailwind content scanning;
  • atomic CSS;
  • CSS splitting.

Side Effects и CSS

CSS считается side effect.

Импорт:

import './style.css'

не экспортирует значения, а изменяет состояние страницы.

Поэтому bundler не удаляет такие импорты как неиспользуемые.


Порядок подключения CSS

Порядок импортов влияет на итоговый результат.

Пример:

import './base.css'
import './theme.css'
import './overrides.css'

Последний импорт имеет наибольший приоритет при одинаковой специфичности.


Проблемы циклических импортов

Нежелательно создавать циклические зависимости:

A.js -> styleA.css
B.js -> styleB.css
A.js -> B.js

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

  • дублирование CSS;
  • непредсказуемый порядок;
  • проблемы HMR.

Импорт CSS через условную логику

Статический импорт:

import './theme-dark.css'

выполняется всегда.

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

if (darkMode) {
    await import('./theme-dark.css')
}

Это позволяет загружать темы по требованию.


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

Часто CSS импортируется ради централизованных переменных.

:root {
    --color-primary: #2563eb;
}

После импорта:

import './variables.css'

переменные становятся доступны глобально.


Интеграция с Tailwind CSS

Tailwind обычно подключается через CSS-файл:

@tailwind base;
@tailwind components;
@tailwind utilities;

Импорт:

import './style.css'

Vite обрабатывает Tailwind через PostCSS pipeline.


Ошибки при импорте CSS

Неверный путь

import './styles.css'

Ошибка:

Failed to resolve import

Причины:

  • файл отсутствует;
  • неверное расширение;
  • неправильная директория.

Отсутствует Sass

import './style.scss'

Ошибка:

Preprocessor dependency "sass" not found

Не установлен пакет sass.


CSS Module импортирован неправильно

Неверно:

import './Button.module.css'

Правильно:

import styles from './Button.module.css'

Архитектура CSS в проектах Vite

Популярная структура:

src/
├── styles/
│   ├── base/
│   ├── components/
│   ├── layouts/
│   ├── themes/
│   ├── utilities/
│   └── global.css

Практика организации импортов

Часто применяется такой порядок:

import './reset.css'
import './variables.css'
import './base.css'
import './utilities.css'
import './components.css'

Это делает каскад более предсказуемым.


Производительность CSS в Vite

Vite ускоряет работу со стилями благодаря:

  • ESM;
  • мгновенному HMR;
  • ленивой загрузке модулей;
  • оптимизированному build pipeline;
  • CSS code splitting;
  • быстрому dependency graph.

Особенно заметна разница в крупных проектах с большим количеством компонентов и CSS-файлов.