Перейти к содержимому
v2.5.0
English
Русский
Документация

Темы

VegaUI поставляет отдельный слой темы в @vega-ui/theme-core. Точка входа пакета — packages/theme/src/index.css, она импортирует и light.css, и dark.css.

Модель темы

Темы основаны на классах:

  • .light: семантические значения светлой темы
  • .dark: семантические значения тёмной темы

Каждая тема сначала импортирует @vega-ui/tokens-core, а затем сопоставляет исходные шкалы токенов с семантическими переменными приложения, например:

  • --background-color
  • --text-color
  • --focus-color
  • --surface-primary
  • --surface-secondary
  • --border-color
  • --fills-primary
  • --label-primary

Ключевые семантические переменные

Это основные переменные, на которые в первую очередь должны опираться код приложения и стили компонентов.

ПеременнаяРольТипичные потребители
--background-colorбазовый цвет холста приложенияфон оболочки приложения, контраст бегунка на дорожке, собственная раскладка страниц
--text-colorцвет содержимого по умолчаниюText, Heading, значения полей, иконки-триггеры, строки опций
--focus-colorцвет обводки фокусакнопки, ссылки, слайдеры, радиокнопки, чекбоксы, сегментированный контрол
--surface-primaryосновная поверхность контейнераDialogContent, DrawerContent, SheetContent, PopoverContent
--surface-secondaryплавающая или временная поверхностьSelectListbox, TooltipContent, TooltipArrow
--border-colorструктурная рамка по умолчаниюCard, Fieldset, TableRow, CheckboxCard
--border-color-hoverакцент рамки при взаимодействииизменение рамки при наведении у поверхностей, оформленных рамкой
--color-errorобратная связь о валидации и ошибкахTextField, TextArea, PinField, HelperText
--fills-primaryакцентная заливка выбранногоотмеченный Checkbox, отмеченный Radio, прогресс в page control
--fills-secondaryнейтральная дорожка или приглушённая заливкаProgress, Meter, MeterStack, Slider, Code, выключенный Switch
--label-primaryвыразительная подпись индикатораактивные индикаторы page control и производные акцентные заливки
--label-secondaryприглушённый второстепенный тексттекст legend в Fieldset, цвет текста Code, второстепенные метаданные
--disable-text-colorосновное содержимое в отключённом состояниитекст отключённых кнопок, значения отключённых полей, отключённые сегменты
--disable-background-colorповерхность отключённого элемента управленияотключённые TextField, TextArea, Select, Checkbox, Switch, ButtonBase
--surface-shadowтень приподнятой поверхностиDialog, Drawer, Sheet, Popover, Tooltip, SelectListbox

Типы семантических токенов

«Ключевые семантические переменные» — это слой быстрой справки. Этот раздел — слой классификации: он группирует переменные темы по семантическим семействам, чтобы систему было проще расширять и понимать.

ТокенСемантический типЗначение в интерфейсе
--fills-primaryaccent-soft-fillосновная акцентная заливка для выбранного или активного интерфейса
--fills-primary-hoveraccent-soft-fill-hoverсостояние наведения основной акцентной заливки
--fills-primary-activeaccent-soft-fill-activeактивное состояние основной акцентной заливки
--fills-secondaryneutral-track-fillнейтральная заливка для дорожек, направляющих и приглушённых контейнеров
--fills-secondary-hoverneutral-track-fill-hoverсостояние наведения нейтральных поверхностей-дорожек
--fills-secondary-activeneutral-track-fill-activeактивное состояние нейтральных поверхностей-дорожек
--fills-tertiaryfield-surfaceфон по умолчанию для полей ввода и похожих на поля элементов управления
--fills-tertiary-hoverfield-surface-hoverсостояние наведения поверхностей полей
--fills-tertiary-activefield-surface-activeактивное состояние поверхностей полей
--fills-quaternary-hovermicro-surface-hoverлёгкая заливка при наведении для действий-иконок и микровзаимодействий
--fills-quaternary-activemicro-surface-activeактивное состояние микровзаимодействий
--surface-primarycontainer-surfaceосновная приподнятая поверхность для контейнеров, таких как диалоги или шторки
--surface-secondaryfloating-surfaceплавающая поверхность для списков, поповеров и тултипов
--surface-shadowelevation-shadowтень для приподнятых поверхностей
--text-colorcontent-primaryчитаемый цвет содержимого по умолчанию
--text-color-inversecontent-on-accentчитаемый цвет содержимого на акцентном фоне
--label-primarylabel-strongцвет выразительной подписи или индикатора
--label-secondarylabel-mutedцвет второстепенной подписи или метаданных
--label-tertiarylabel-subtleцвет placeholder, подсказок и приглушённых подписей
--border-colorborder-defaultцвет структурной рамки по умолчанию
--border-color-hoverborder-hoverсостояние наведения структурных рамок
--border-color-activeborder-activeактивное состояние структурных рамок
--disable-background-colordisabled-surfaceфон и заливка поверхности в отключённом состоянии
--disable-text-colordisabled-contentцвет основного текста или значения в отключённом состоянии
--disable-label-text-colordisabled-subtle-contentцвет второстепенного текста, подсказки или placeholder в отключённом состоянии
--disable-border-colordisabled-borderцвет рамки или индикатора в отключённом состоянии
--focus-colorfocus-ringцвет кольца фокуса и обводки
--color-errorfeedback-errorцвет обратной связи об ошибках и валидации
--overlaybackdrop-overlayзатемнение фона для модальных слоёв и оверлеев
--separator-opaqueseparator-strongвидимые разделители, ручки и делители

Семантические семейства

В первую очередь думайте о переменных темы через эти семейства:

  • fills-*: семантика интерактивных заливок для выбранных, наведённых, нажатых или похожих на поля поверхностей
  • surface-*: семантика контейнеров и плавающих поверхностей для оверлеев и приподнятого интерфейса
  • text-* и label-*: семантика читаемого содержимого и подписей интерфейса
  • border-*: семантика структурных границ и акцентов рамки
  • disable-*: семантика поверхности, содержимого и рамки в отключённом состоянии
  • focus-color, color-error, overlay, separator-*: системная семантика и обратная связь о состоянии

Семантические типы на практике

Эти семантические типы выведены из того, как переменные на самом деле используются в UI-пакете:

  • accent-soft-fill: выбранные или отмеченные состояния, например Checkbox, Radio и прогресс в page control
  • neutral-track-fill: дорожки и нейтральные полосы, например Progress, Meter, MeterStack и Slider
  • field-surface: элементы управления, похожие на поля ввода, например TextField, TextArea, PinField и SelectCombobox
  • micro-surface-*: малозаметные поверхности наведения и активного состояния для иконок-кнопок, кнопок-триггеров и элементов пикеров
  • container-surface: основные поверхности оверлеев или панелей, например DialogContent, DrawerContent и SheetContent
  • floating-surface: плавающие поверхности содержимого, например SelectListbox, TooltipContent и PopoverContent
  • content-*, label-*, border-* и disable-*: семантика текста, подписей, рамок и отключённого состояния, общая для всего набора

Используйте этот раздел, чтобы ответить на вопрос «какой класс семантического токена мне здесь нужен?», а затем выберите конкретное имя переменной в разделе «Ключевые семантические переменные».

Как применить тему

Поставьте класс темы на <html>:

<html class="light">

Dialog, Drawer и Sheet рендерятся в document.body, поэтому класс на внутренней обёртке до них не доходит.

Оболочка приложения с переключателем темы

import { useEffect, useState } from 'react';
import { Button } from '@vega-ui/react';

type ThemeName = 'light' | 'dark';

export function ThemeSwitcher() {
  const [theme, setTheme] = useState<ThemeName>('light');

  useEffect(() => {
    document.documentElement.classList.remove('light', 'dark');
    document.documentElement.classList.add(theme);
  }, [theme]);

  return (
    <Button variant='secondary' appearance='ghost' onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      Switch to {theme === 'light' ? 'dark' : 'light'}
    </Button>
  );
}

Задайте странице фон и цвет текста темы:

body {
  background: var(--background-color);
  color: var(--text-color);
}

Обёртка с другим классом темы оформляет своё поддерево, но Dialog, Drawer и Sheet, открытые из неё, всё равно берут тему <html>.

Настройка темы

Самый безопасный путь настройки — определить собственный класс темы и переопределить в нём семантические переменные.

@import '@vega-ui/theme-core';

.brand-sunrise {
  --background-color: #fffaf3;
  --text-color: #251b10;
  --surface-primary: #fffdf9;
  --surface-secondary: #fff7ec;
  --border-color: #e7d7c2;
  --focus-color: var(--color-orange-accent-400);
  --fills-primary: color-mix(in oklab, var(--color-orange-accent-500) 16%, transparent);
  --fills-primary-hover: color-mix(in oklab, var(--color-orange-accent-500) 22%, transparent);
  --label-secondary: #7a6653;
}

Затем поставьте этот класс на <html> так же, как .light или .dark.

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

Поведение светлой и тёмной темы

Светлая и тёмная темы используют одни и те же имена семантических переменных. Основное различие — в том, как эта семантика сопоставляется с исходной шкалой токенов.

В частности, акцентные цвета в тёмном режиме инвертированы. Например, --color-blue-accent-100 указывает на более светлый исходный синий в светлом режиме и на более тёмный — в тёмном. Поэтому в стилях компонентов следует предпочитать семантические акцентные переменные шагам исходной палитры.

Рекомендации

  • ставьте класс темы на <html>, а не на обёртку или отдельные компоненты
  • по возможности используйте семантические переменные в CSS компонентов
  • не пишите светлые/тёмные переопределения для конкретного компонента, если подходящая семантическая переменная темы уже есть
  • настраивайте семантические переменные, прежде чем трогать локальные переменные компонентов --component-*