НачалоОсновыКомпонентыТексты

Цвет

Выбирайте цвет по роли, а не по значению. Каждый цветовой токен следует за темой и основным цветом, поэтому одни и те же имена работают везде.

РуководствоТокены

Принципы

  • Сначала нейтральное. Поверхности, текст и рамки серые и белые. Цвета мало, поэтому там, где он есть, он что-то значит: главное действие, статус, категорию.
  • Выбирайте по роли. Берите токен роли, например text/default или fill/accent. Сырая палитра (gray-100, blue-500) за темой не следует.
  • Темы и основной цвет меняют значения, а не имена. Один и тот же токен работает в светлой, тёмной и контрастной теме и с любым основным цветом.
  • Не передавайте смысл одним цветом. Добавьте к статусу, выбору или ошибке иконку, текст или форму.

Имена токенов

Имя цветового токена читается так: роль / намерение / уровень / состояние. Лишние части опускаются.

  • Роль: surface, text, icon, border, fill, state.
  • Намерение: accent, success, warning, error, info. У нейтральных токенов намерения в имени нет: text/default, а не text/neutral/default.
  • Уровень: например secondary, subtle, strong, raised.
  • Состояние: например hover, active, disabled, on-fill.

В CSS косые черты заменяются дефисами:

Токен CSS-переменная
text/default var(--text-default)
text/secondary var(--text-secondary)
fill/accent/hover var(--fill-accent-hover)
surface/error var(--surface-error)
text/accent/on-fill var(--text-accent-on-fill)
.card {
  background: var(--surface-default);
  color: var(--text-default);
  border: 1px solid var(--border-default);
}

Темы

  • Светлая: нейтральная основа на белом. Глубину дают ступени серого.
  • Тёмная: настроена отдельно, это не перевёрнутая светлая. Чем выше слой, тем он светлее: страница самая тёмная, всплывающие панели самые светлые.
  • Контрастная: текст, рамки и заливки сильнее, а наведение, нажатие и выбор различаются между собой. Эта тема везде выдерживает контраст WCAG.

Как выбрать тему

Задайте data-theme на <html>: light, dark или high-contrast.

<html data-theme="dark">

Без атрибута страница светлая, но если система просит больше контраста, тема сама становится контрастной. Заданное вами значение всегда главнее.

data-theme Система просит больше контраста Система молчит
не задан контрастная светлая
light светлая светлая
dark тёмная тёмная
high-contrast контрастная контрастная

data-theme работает и на части страницы:

Publish Save draft
<div data-theme="dark" style="background: var(--surface-page); color: var(--text-default); padding: var(--space-16)">
  <tk-button variant="primary">Publish</tk-button>
  <tk-button>Save draft</tk-button>
</div>

Режим принудительных цветов (высокая контрастность Windows) к этим темам не относится: система заменяет цвета на цвета пользователя.

Основной цвет и акцент

Акцент (основная кнопка, ссылки, отмеченные элементы управления, рамка фокуса) берёт оттенок из одного основного цвета. Задайте data-primary на <html> рядом с data-theme:

<html data-theme="light" data-primary="purple">

Значения: blue (по умолчанию), orange, green, mint, teal, indigo, purple, brown, gray, black.

Publish Preview Email me updates
<tk-button variant="primary">Publish</tk-button>
<tk-button variant="ghost">Preview</tk-button>
<tk-checkbox checked>Email me updates</tk-checkbox>
  • black даёт монохромный акцент: в светлой и контрастной теме основная кнопка чёрная с белым текстом, в тёмной белая с чёрным.
  • Текст на акцентной заливке (text/accent/on-fill) белый для всех основных цветов, кроме orange: там он чёрный.
  • info не акцент. info всегда синий, а акцент следует за основным цветом. Не подменяйте одно другим, даже если основной цвет синий.

Числа в таблице — ступени шкалы основного цвета в светлой, тёмной и контрастной теме.

Токен Для чего Светлая Тёмная Контрастная
fill/accent основная кнопка, отмеченные чекбокс, радиокнопка и переключатель, слайдер 500 500 600
fill/accent/hover наведение на акцентную заливку 600 400 700
fill/accent/active нажатие на акцентную заливку 600 400 800
fill/accent/disabled не используется: отключённые элементы берут surface/disabled 200 800 300
text/accent ссылки, текст кнопки ghost 600 400 800
text/accent/hover наведение на ссылку и кнопку ghost 800 200 900
text/accent/on-fill текст на fill/accent белый или чёрный белый или чёрный белый или чёрный
icon/accent акцентные иконки 600 400 700
icon/accent/on-fill иконки на fill/accent как text/accent/on-fill
border/accent акцентная грань, например у ручки изменения размера во время перетаскивания 500 500 700
border/accent/focus рамка фокуса и граница поля в фокусе 500 500 800
state/accent/hover акцентный слой наведения 600, 10% 500, 10% 800, 18%
state/accent/press акцентный слой нажатия 600, 10% 500, 10% 800, 46%
state/accent/on акцентный слой выбора 600, 10% 500, 10% 800, 46%

В светлой и тёмной теме fill/accent/active равен fill/accent/hover, так что отдельного вида нажатия у основной кнопки там нет. Рамке фокуса посвящена своя страница: Focus.

Роли

Роль Что окрашивает
surface фоны: страницу, карточки, панели, всплывающие окна
text всё, что читают
icon самостоятельные иконки
border контуры, разделители, выбор
fill небольшие элементы со своей заливкой, например дорожку переключателя или сплошной бейдж
state полупрозрачные слои наведения, нажатия и выбора поверх всего перечисленного

Поверхность

Токен Для чего Светлая Тёмная Контрастная
surface/page холст страницы white gray-950 gray-50
surface/default блоки контента и карточки white gray-900 gray-50
surface/subtle слегка утопленная область внутри блока gray-50 gray-800 gray-100
surface/raised всплывающие панели: меню, поповеры, диалоги white gray-900 gray-50
surface/sunken углубления и дорожки, например дорожка прогресса gray-100 gray-950 gray-200
surface/inverse панель в обратном тоне: подсказка, тост gray-900 gray-50 gray-950
surface/disabled заливка отключённого элемента gray-50 gray-900 gray-100
surface/backdrop затемнение страницы под модальным диалогом, и ничего больше gray-950, 50% black, 60% gray-950, 60%

У поверхностей нет токенов наведения и выбора: для этого есть слои состояний ниже.

Текст

Токен Для чего Светлая Тёмная Контрастная
text/default заголовки и основной текст gray-950 gray-50 gray-950
text/secondary подписи, метаданные gray-700 gray-300 gray-900
text/tertiary время, счётчики gray-600 gray-400 gray-800
text/placeholder подсказка в пустом поле gray-500 gray-500 gray-600
text/disabled текст отключённого элемента gray-400 gray-600 gray-500
text/inverse текст на surface/inverse gray-50 gray-950 gray-50
text/on-fill текст на fill/default gray-950 white gray-950

Иконки

Каждый токен icon/* работает в паре с токеном text/* того же уровня. Иконкам нужен контраст 3:1, а не 4.5:1, поэтому в светлой и контрастной теме иконка на ступень светлее своего текста, а в тёмной совпадает с ним.

Токен Светлая Тёмная Контрастная
icon/default gray-900 gray-50 gray-900
icon/secondary gray-600 gray-300 gray-800
icon/tertiary gray-500 gray-400 gray-700
icon/disabled gray-300 gray-600 gray-400
icon/inverse gray-50 gray-950 gray-50
icon/on-fill как text/on-fill

Рамки

Токен Для чего Светлая Тёмная Контрастная
border/subtle разделители внутри блока; граница полей и кнопок outline gray-100 gray-700 gray-600
border/default контуры контейнеров и элементов управления gray-200 gray-600 gray-700
border/strong грани, которые должны быть заметны, например разделитель в split button gray-300 gray-400 gray-800
border/selected выбранный элемент gray-800 gray-200 gray-900
border/inverse рамка или рамка фокуса на surface/inverse gray-50 gray-950 gray-50
border/disabled рамка отключённого элемента gray-100 gray-900 gray-300

Рамка фокуса — это border/accent/focus, она в разделе Основной цвет и акцент.

Заливки

Токен Для чего Светлая Тёмная Контрастная
fill/default нейтральная заливка элемента, например выключенная дорожка переключателя gray-100 gray-800 gray-200
fill/hover её наведение gray-200 gray-700 gray-300
fill/active её нажатие gray-300 gray-600 gray-400
fill/selected выбранная нейтральная заливка gray-300 gray-600 gray-400
fill/disabled отключённая заливка gray-100 gray-900 gray-200

Текст и иконки на заливке берут её пару on-fill: text/on-fill на fill/default, text/accent/on-fill на fill/accent, text/error/on-fill на fill/error.

Слои состояний

Наведение, нажатие и выбор — полупрозрачные слои поверх того, что элемент уже показывает. Рисуйте их через background-image, а собственный background-color элемента оставляйте. У каждого слоя есть готовый градиент: --state-layer-hover, --state-layer-press, --state-layer-on, --state-layer-on-hover, акцентные (--state-layer-accent-hover, -press, -on) и для ошибки (--state-layer-error-hover, -press).

.row:hover { background-image: var(--state-layer-hover); }
.row[aria-selected='true'] { background-image: var(--state-layer-on); }

Не задавайте такому элементу сокращённое свойство background: оно сбрасывает background-image и убирает слой.

Токен Для чего Светлая Тёмная Контрастная
state/hover под указателем gray-950, 5% gray-50, 5% gray-950, 13%
state/press во время нажатия gray-950, 5% gray-50, 5% gray-950, 26%
state/on выбрано, включено или текущее gray-950, 5% gray-50, 5% gray-950, 38%
state/on-hover включённый элемент под указателем gray-950, 9.75% gray-50, 9.75% gray-950, 38%

В светлой и тёмной теме наведение, нажатие и выбор дают одинаковый оттенок. Отмечайте выбранный элемент чем-то ещё: border/selected, галочкой или более жирным текстом. В контрастной теме они различаются.

Цвета статусов

Статусы сохраняют оттенок при любом основном цвете: успех зелёный, предупреждение оранжевое, ошибка красная, информация синяя.

Payment received. Your trial ends in 3 days. The upload failed. Try again. Reports update every hour.
<tk-section-message tone="success">Payment received.</tk-section-message>
<tk-section-message tone="warning">Your trial ends in 3 days.</tk-section-message>
<tk-section-message tone="error">The upload failed. Try again.</tk-section-message>
<tk-section-message tone="info">Reports update every hour.</tk-section-message>
Paid Due soon Overdue New
<tk-badge tone="success">Paid</tk-badge>
<tk-badge tone="warning">Due soon</tk-badge>
<tk-badge tone="error" treatment="solid">Overdue</tk-badge>
<tk-badge tone="info" treatment="solid">New</tk-badge>

В каждой ячейке ступень оттенка статуса: светлая · тёмная · контрастная.

Токен success (зелёный) warning (оранжевый) error (красный) info (синий)
surface/{status}: тонированный фон 50 · 900 · 100 50 · 900 · 100 50 · 900 · 100 50 · 900 · 100
text/{status} 600 · 400 · 800 600 · 400 · 800 600 · 400 · 800 600 · 400 · 800
icon/{status} 600 · 400 · 700 600 · 400 · 700 600 · 400 · 700 600 · 400 · 700
border/{status} 300 · 500 · 600 300 · 500 · 600 600 · 400 · 600 300 · 500 · 600
fill/{status}: сплошная заливка 600 · 500 · 700 500 · 500 · 700 600 · 500 · 700 600 · 600 · 700
text/{status}/on-fill, icon/{status}/on-fill белый чёрный · чёрный · белый белый белый

У error есть и токены взаимодействия:

Токен Для чего Светлая Тёмная Контрастная
state/error/hover наведение на опасную кнопку или пункт меню red-600, 10% red-500, 10% red-800, 18%
state/error/press нажатие на них же; равно наведению red-600, 10% red-500, 10% red-800, 18%
fill/error/hover наведение на сплошную красную заливку; компоненты его не используют red-700 red-600 red-800
fill/error/active нажатие на сплошную красную заливку; компоненты его не используют red-800 red-700 red-900

Категориальная палитра

Тринадцать цветов различают категории: теги, метки, серии графиков, аватары. Статуса они не несут: красный тег не ошибка.

Research Design Marketing Sales Unassigned
<tk-tag color="purple">Research</tk-tag>
<tk-tag color="teal">Design</tk-tag>
<tk-tag color="orange">Marketing</tk-tag>
<tk-tag color="green">Sales</tk-tag>
<tk-tag color="gray">Unassigned</tk-tag>

Цвета: red, orange, yellow, green, mint, teal, cyan, blue, indigo, purple, pink, brown, gray. У каждого три токена; числа — ступени этого цвета: светлая · тёмная · контрастная.

Токен CSS-переменная Для чего Ступени
categorical/{color}/surface --{color}-surface фон метки 100 · 900 · 100
categorical/{color}/text --{color}-text текст метки 700 · 300 · 900; в светлой 800 для orange, yellow, green, mint, teal, cyan
categorical/{color}/border --{color}-border необязательный контур 400 · 500 · 700
  • Текст на своём фоне даёт не меньше 5:1 в любой теме.
  • Контур декоративный: в светлой теме он ниже 3:1. Не передавайте им смысл.
  • На одном экране держите не больше пяти-шести категориальных цветов: больше трудно различить.
  • Оси и подписи графика берите из нейтральных токенов.

Палитра подсветки кода

Code block раскрашивает код токенами syntax/*. Как и категориальные цвета, они не несут статуса: строка зелёная, но это не success.

// Show a price in dollars
function formatPrice(amount) {
  return '$' + amount.toFixed(2);
}
<tk-code-block language="js"><pre>// Show a price in dollars
function formatPrice(amount) {
  return '$' + amount.toFixed(2);
}</pre></tk-code-block>
Токен Светлая Тёмная Контрастная
syntax/surface gray-50 gray-950 white
syntax/keyword purple-700 purple-300 purple-800
syntax/string green-700 green-300 green-800
syntax/comment gray-700 gray-400 gray-700
syntax/number orange-700 orange-300 orange-800
syntax/function blue-700 blue-300 blue-800
syntax/class teal-700 teal-300 teal-800
syntax/variable red-700 red-300 red-800
syntax/punctuation gray-800 gray-300 gray-800

Каждый цвет подсветки даёт не меньше 4.5:1 на syntax/surface в любой теме.

Пары

Берите фон вместе с его парными токенами, и контраст уже заложен.

Сочетание Фон Текст Иконка Рамка
Карточка surface/default text/default icon/default border/default
Выбранная строка её поверхность + слой state/on text/default icon/default border/selected или галочка
Нейтральная заливка fill/default text/on-fill icon/on-fill нет
Основная кнопка fill/accent text/accent/on-fill icon/accent/on-fill нет
Ссылка любая поверхность text/accent нет нет
Сообщение о статусе surface/{status} text/{status} icon/{status} border/{status}
Сплошной бейдж fill/{status} text/{status}/on-fill icon/{status}/on-fill нет
Подсказка, тост surface/inverse text/inverse icon/inverse border/inverse
Отключённый элемент surface/disabled text/disabled icon/disabled border/disabled
Тег categorical/{color}/surface categorical/{color}/text нет categorical/{color}/border, по желанию

Доступность

Уже встроено:

  • У каждой роли фона есть парные токены текста и иконок; пары выше выдерживают свой порог контраста, кроме пределов ниже.
  • Контрастная тема везде выдерживает контраст WCAG, и тот, кто попросил у системы больше контраста, получает её сам.
  • Отключённый вид задают отдельные токены, а не opacity.
  • Подсказка в поле и текст отключённых элементов намеренно ниже 4.5:1: это не контент.

Ваша часть:

  • Не передавайте смысл одним цветом; добавьте иконку, текст или форму.
  • Проверяйте пары, которых нет на этой странице: 4.5:1 для текста; 3:1 для крупного текста (24px или 18.66px жирным), иконок и рамок, несущих смысл.
  • Берите text/* для текста и icon/* для иконок. Цветам иконок хватает 3:1, для текста они бывают слишком светлыми.

Измеренные пары

Светлая тема, синий основной цвет.

Фон Передний план Контраст
surface/default text/default 17.36:1
surface/default text/secondary 6.66:1
surface/default text/tertiary 4.59:1
surface/default text/accent 5.49:1
surface/error text/error 4.63:1
surface/info text/info 5.05:1
fill/default text/on-fill 13.06:1
fill/accent text/accent/on-fill 4.02:1
fill/success text/success/on-fill 4.66:1
fill/warning text/warning/on-fill 9.55:1
fill/error text/error/on-fill 5.07:1
fill/info text/info/on-fill 5.49:1

Пределы контраста

Эти пары не дотягивают в светлой или тёмной теме. Контрастная тема выдерживает минимумы.

  • Текст статуса на своём фоне: text/success 4.29:1 и text/warning 3.02:1 в светлой теме, ниже 4.5:1. text/warning даёт 3.30:1 даже на белом.
  • Акцентный текст: text/accent даёт 3.30:1 на белом с основным цветом orange. В тёмной теме на surface/subtle и surface/raised он ниже 4.5:1 со всеми основными цветами, кроме orange и black; ниже всех indigo, 2.47:1.
  • Текст на акцентной заливке: не меньше 3:1 с любым основным цветом (ниже всех gray, 3.26:1), но ниже 4.5:1 с несколькими, например у blue 4.02:1.
  • Граница поля и кнопки outline (border/subtle): 1.33:1 в светлой и 2.00:1 в тёмной, ниже 3:1; 4.22:1 в контрастной. В светлой теме на surface/sunken она пропадает.
  • border/strong: 2.02:1 на белом в светлой теме, ниже 3:1.
  • Текст опасной кнопки при наведении и нажатии: 3.94:1 в светлой теме.
  • Рамка фокуса: ниже 3:1 с некоторыми основными цветами на некоторых поверхностях. Подробнее в Focus.
  • Выбранное и наведённое выглядят одинаково в светлой и тёмной теме. Отмечайте выбор рамкой, галочкой или более жирным текстом.

Можно / нельзя

✅ Можно ❌ Нельзя
Ставить text/accent/on-fill на fill/accent Ставить text/default на акцентную заливку
Заливать fill/* только небольшие элементы Делать заливку фоном страницы или панели
Показывать отключённый элемент токенами */disabled Приглушать его через opacity
Брать цвета статусов из success, warning, error, info Обозначать статус акцентом
Различать метки категориальным цветом Обозначать ошибку красным тегом
Отмечать выбранное border/selected или галочкой Полагаться только на оттенок state/on
Рисовать слои состояний через background-image Задавать background элементу со слоем состояния
Брать один токен для всех тем Вписывать тему в имя, например surface-default-dark

Примитивы

Под ролями лежит палитра: 13 оттенков (red, orange, yellow, green, mint, teal, cyan, blue, indigo, purple, pink, brown, gray), у каждого 11 ступеней от 50 до 950, плюс white и black. В CSS: var(--blue-500).

Примитивы не меняются с темой и основным цветом, поэтому везде, где подходит токен роли, берите его. Одна и та же ступень выглядит примерно одинаково тяжёлой в любом оттенке, но контраст всё равно разный: orange и yellow на той же ступени светлее, чем blue или gray.

Все значения с контрастом к белому и чёрному: Primitive colors.

  • Focus: рамка фокуса и её цвет.
  • Elevation: тени, которые поднимают всплывающие поверхности.
  • Badge, Section message и Banner: цвета статусов в деле.
  • Tag: категориальная палитра в деле.