Темная тема в Vue: реализация с CSS‑переменными и LocalStorage
Внедрение тёмных тем в веб‑приложения перестало быть «дополнением» и стало стандартной опцией интерфейса. Пользователи переключаются между светлой и тёмной темами не только из эстетических соображений, но и по практическим причинам: тёмная тема снижает нагрузку на глаза в условиях низкой освещённости и экономит энергию на экранах OLED/AMOLED.
В этом материале вы найдёте пошаговую инструкцию для Vue‑приложения: от создания тестового приложения до продвинутых практик, учитывающих предпочтения системы, синхронизацию между вкладками, доступность и возможные альтернативы.
Почему имеет смысл добавить тёмную тему
- Комфорт для пользователя в условиях низкой освещённости.
- Экономия батареи на OLED/AMOLED устройствах (чёрные пиксели не потребляют энергию).
- Совместимость с системными настройками (предпочтения пользователя на уровне ОС).
- Современные ожидания: пользователи ждут опции переключения темы.
Важно: выбор места хранения предпочтений влияет на поведение при обновлении приложения и синхронизации между вкладками.
Настройка тестового приложения
Чтобы воспроизвести примеры, создайте простое Vue‑приложение.
Откройте терминал и выполните:
npm init vue@latestЭта команда установит последний пакет create-vue и создаст каркас приложения. Для целей этого руководства дополнительные опции (TypeScript, маршрутизация и т.д.) можно не выбирать — примеры работают в минимальной конфигурации.
В файле src/App.vue добавьте стартовый шаблон (мы будем использовать классы для стилизации):
Welcome to My Vue App
This is a simple Vue app with some text and styles.
Styled Text
Этот минимальный шаблон пригодится для демонстрации стилей и логики переключения.
Стилизация через CSS‑переменные
CSS‑пользовательские свойства (CSS variables) делают темы гибкими: изменяя значение переменной в одном месте, вы переходите между наборами цветов во всём интерфейсе.
Создайте файл src/assets/styles.css и добавьте базовые переменные для светлой и тёмной тем.
/* styles.css */
:root {
--background-color: #ffffff; /* White */
--text-color: #333333; /* Dark Gray */
--box-background: #007bff; /* Royal Blue */
--box-text-color: #ffffff; /* White */
--toggle-button: #007bff; /* Royal Blue */
}
[data-theme='true'] {
--background-color: #333333; /* Dark Gray */
--text-color: #ffffff; /* White */
--box-background: #000000; /* Black */
--box-text-color: #ffffff; /* White */
--toggle-button: #000000; /* Black */
}
* {
background-color: var(--background-color);
text-align: center;
color: var(--text-color);
padding: 20px;
font-family: Arial, sans-serif;
transition: background-color 0.3s, color 0.3s;
}
.header {
font-size: 24px;
margin-bottom: 20px;
}
.styled-box {
background-color: var(--box-background);
color: var(--box-text-color);
padding: 10px;
border-radius: 5px;
margin: 20px 0;
}
.styled-text {
font-size: 18px;
font-weight: bold;
}
.toggle-button {
background-color: var(--toggle-button);
color: #fff;
border: none;
border-radius: 3px;
cursor: pointer;
padding: 5px 10px;
}Имейте в виду:
- :root задаёт значения по умолчанию (светлая тема).
- атрибутный селектор [data-theme=’true’] переопределяет переменные для тёмной темы.
- переходы (transition) создают гладкую анимацию при переключении тем.
В main.js импортируйте этот файл стилей:
// main.js
import './assets/styles.css'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')Логика переключения тёмной темы в Vue
Добавьте в App.vue блок скрипта на Composition API. Мы будем хранить флаг darkMode в реактивной ссылке (ref) и синхронизировать его с localStorage.
Ключевые моменты:
- Мы сначала пытаемся прочитать значение из localStorage. Если его нет, используем системное prefers-color-scheme.
- При изменении системной настройки (например, пользователь переключил тему в ОС) и если пользователь не задавал своё явное предпочтение, тема обновится автоматически.
- Используем событие storage для синхронизации между вкладками.
- Обёртка try/catch исключает ошибку в окружениях, где localStorage недоступен.
Финальный шаблон App.vue с привязкой
Обновим шаблон, чтобы он использовал переменную darkMode и кнопку для переключения.
Welcome to My Vue App
This is a simple Vue app with some text and styles.
Styled Text
После запуска npm run dev вы увидите приложение и сможете переключать тему по кнопке.
Дальнейшие улучшения и практические советы
Accessibility (доступность)
- Проверяйте контрастность текста с фоном по стандарту WCAG (минимум 4.5:1 для основного текста).
- Избегайте использования только цвета для передачи информации (подчёркивайте или добавляйте иконки).
- Тестируйте на реальных устройствах и с программами чтения экрана.
Плавные переходы и перформанс
- Ограничьте анимируемые свойства: лучше менять цвет и фильтры, но не layout‑свойства.
- Избегайте обработки всех элементов через универсальный селектор, если у вас большое приложение — переключение темы может привести к переработке большого дерева DOM.
Изображения и медиаконтент
- Тёмная тема может потребовать альтернативных изображений (например, логотипа с белым контуром).
- Для векторных изображений (SVG) удобнее менять цвет через CSS (fill, stroke).
SSR и гидрация
- Для серверного рендеринга хранить предпочтение в localStorage нельзя на сервере. Подумайте о cookie или встроенной метке в HTML (например, data-theme на ) при первом рендере.
- Иначе возможен эффект «мигания» (FOUC) при гидрации на клиенте.
Синхронизация между вкладками
- Мы уже добавили обработчик storage — это простая и надёжная стратегия.
Альтернативные подходы
- Класс вместо атрибута: document.documentElement.classList.toggle(‘dark’) и в CSS использовать .dark { –background-color: … }. Класс удобнее при интеграции с фреймворками и утилитами.
- prefers-color-scheme как единственный источник правды: хорошо для случаев, когда вы не хотите предоставлять пользовательскую настройку.
- CSS-фреймворки (Tailwind, Vuetify): у многих есть встроенные механизмы тёмной темы — используйте их, если готовы принять зависимость.
Когда один подход не подходит:
- Если приложение рендерится на сервере и важно показать правильную тему сразу, храните выбор в cookie и считывайте на сервере.
- Если требуется учёт профилей пользователя (аутентификация), храните настройку в профиле на сервере и применяйте её после входа.
Мини‑методология: 7 шагов внедрения тёмной темы
- Определите набор цветовых переменных (фон, текст, акценты, тени).
- Реализуйте CSS‑переменные для светлой и тёмной тем.
- Добавьте переключатель в UI и реактивное состояние (Vue ref).
- Сохраните выбор в localStorage (или cookie/профиль).
- Поддержите prefers-color-scheme и слушайте его изменения.
- Тестируйте контрастность и доступность.
- Обновите изображения/иконки для обеих тем.
Чеклисты по ролям
Разработчик:
- Реализовал CSS‑переменные и переключатель.
- Добавил сохранение в localStorage и синхронизацию между вкладками.
- Обработал недоступность localStorage.
Дизайнер:
- Утвердил палитры для обеих тем.
- Проверил контрастность по WCAG.
- Подготовил альтернативные логотипы/изображения.
QA:
- Проверил переключение локально и между вкладками.
- Проверил поведение при системном переключении темы.
- Проверил доступность и контрастность.
Критерии приёмки
- Переключение темы работает и сохраняется между перезагрузками.
- При отсутствии явного выбора — используется системная настройка.
- Переключение между вкладками синхронизируется.
- Контрастность текста соответствует требованиям доступности.
- Нет заметной подтормаживания при переключении темы на целевых устройствах.
Тестовые сценарии и случаи приёмки
- Новый пользователь без сохранённой настройки. Ожидается: тема совпадает с системной настройкой.
- Пользователь переключил тему вручную. Ожидается: выбор сохраняется в localStorage и применяется после перезагрузки.
- Пользователь сменил тему в другой вкладке. Ожидается: текущая вкладка автоматически применяет новое значение.
- LocalStorage недоступен (приватный режим). Ожидается: приложение не падает, тема определяется по prefers-color-scheme.
- SSR: начальная загрузка не должна показать «мигание» другой темы дольше допустимого времени.
Полезные сниппеты
- Быстрый способ применить тему через класс:
const setDark = (isDark) => {
document.documentElement.classList.toggle('dark', isDark);
};- Пример переключателя с aria‑атрибутами для доступности:
- Запись в cookie для SSR:
// при логине на сервере добавьте cookie: theme=dark или theme=light
// затем на сервере добавьте атрибут data-theme в перед отправкойСовместимость и подводные камни
- Старые браузеры: CSS‑переменные поддерживаются в современных браузерах; для IE потребуется полифилл.
- LocalStorage может быть отключён пользователем или недоступен в приватном режиме — код должен обрабатывать исключения.
- SSR: если тема определяется только на клиенте, возможны визуальные артефакты при начальной загрузке.
Конфиденциальность и хранение настроек
LocalStorage хранит только предпочтение темы (true/false). Это не личные данные, однако имейте в виду:
- Если приложение хранит тему в профиле на сервере, это становится частью персонализированных данных пользователя.
- При использовании cookie для SSR учитывайте настройки SameSite, secure и срок жизни.
Короткая сводка для соцсетей
Темная тема в Vue: как добавить переключатель с помощью CSS‑переменных, сохранить выбор в localStorage, учесть системные предпочтения и не нарушить доступность.
Итог
Тёмная тема — это не только про внешний вид. Это про удобство, экономию энергии на некоторых устройствах и ожидания пользователей. Простой подход с CSS‑переменными и localStorage покрывает многие сценарии, но для больших приложений стоит учесть SSR, хранение в профиле и доступность. Выберите стратегию (атрибут vs класс, localStorage vs cookie) исходя из архитектуры вашего приложения.
Important: тестируйте на реальных устройствах и с инструментами проверки доступности.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone