Цветовые роли
Цветовые роли — это токены, которые называют назначение цвета и связывают его с тоном палитры отдельно для каждой темы. Благодаря ролям одна разметка правильна и в светлой, и в тёмной теме.
Что такое цветовая роль
Цветовая роль — это токен, который называет назначение цвета: «главный акцент», «фон области», «текст на фоне ошибки», «граница контрола». Роль связывает назначение с конкретным тоном палитры отдельно для каждой темы.
Компоненты и утилиты красят только ролями. Кнопка запрашивает --sf-primary,
а конкретный тон определяет тема.
Система ролей основана на подходе Material Design 3 и доработана для веба:
состояния (наведение, выбор, нажатие) выражены не отдельным слоем поверх
элемента, а собственными ролями — -hover, -active, -transparent-*. Их
можно применить обычным CSS-свойством и обычной утилитой.
Система: роль, on-роль, контейнер
Каждая цветовая роль — не один цвет, а семейство, построенное по одной
схеме. Схема одинакова для primary, secondary, tertiary, success,
warning и error. У info те же роли, кроме слоёв состояния
-transparent-*. На примере primary:
| Роль | Работа | Светлая тема | Тёмная тема |
|---|---|---|---|
--sf-primary |
Насыщенная заливка, акцентный текст и иконка | тон 40 | тон 80 |
--sf-primary-hover / -active |
То же при наведении / нажатии | 35 / 30 | 85 / 90 |
--sf-on-primary |
Текст и иконка на --sf-primary |
белый | тон 20 |
--sf-primary-container |
Спокойная плашка в тоне роли | тон 50, 12 % | тон 50, 24 % |
--sf-primary-container-hover / -active |
Плашка при наведении / нажатии | 16 % / 20 % | 28 % / 32 % |
--sf-on-primary-container |
Текст и иконка на плашке | тон 10 | тон 90 |
--sf-on-primary-container-graphic |
Крупная графика на плашке | тон 50 | тон 60 |
--sf-primary-transparent-hover / -select / -active |
Слой состояния поверх любой поверхности | тон 50: 4 / 8 / 12 % | тон 90: 4 / 8 / 12 % |
--sf-primary-transparent-overlay |
Сильная вуаль в тоне роли | тон 50, 24 % | тон 90, 24 % |
--sf-outline-primary |
Граница в тоне роли | тон 50 | тон 60 |
Правила системы:
- Фон и содержимое берутся парой. На
--sf-primaryпишут--sf-on-primary, на--sf-primary-container—--sf-on-primary-container. Пара подобрана так, чтобы держать контраст в обеих темах. Чужая пара (например,--sf-on-surfaceна--sf-primary) может сработать в одной теме и провалиться в другой. - Насыщенная роль и контейнер — две силы одного цвета. Насыщенная заливка — для одного главного действия на экране. Контейнер — для спокойных элементов: тональной кнопки, плашки статуса, выбранной строки.
- Контейнер полупрозрачен. Плашка в тоне роли — тон 50, пропущенный через поверхность, поэтому она одинаково заметна на белой странице, на сером фоне и на поднятой панели (подробно — Прозрачность).
- Тёмная тема — не инверсия. Насыщенная роль в тёмной теме светлее (тон 80), а текст на ней темнее (тон 20). Именно схема тонов делает тёмную тему читаемой.
Как роли использует компонент — на примере кнопки:
| Вид кнопки | Фон | Текст и иконка |
|---|---|---|
Залитая (default) |
--sf-primary |
--sf-on-primary |
Тональная (tonal) |
--sf-primary-container |
--sf-on-primary-container |
Контурная (outline), link |
прозрачный | --sf-primary |
| Отключённая залитая или тональная | --sf-disable |
--sf-on-disable |
Настройка scheme у компонента (см. Настройки: общий язык компонентов) выбирает семейство ролей:
scheme="primary" — семейство primary, scheme="on-surface" — нейтральное
содержимое.
Образцы ниже собраны из переменных текущего выпуска. Переключите светлую и тёмную тему в настройках документации: фон и текст каждой карточки сменятся сами, потому что это роли, а не примитивы.
Акцентные роли
- Primary — главный акцент. Самое важное действие или выбранное состояние. Рекомендуется один-два акцента primary на экране: когда выделено всё, не выделено ничего.
- Secondary — приглушённый родственник primary для частых, повторяющихся элементов: пунктов меню, вкладок, кнопок в списках.
- Tertiary — контрастный к primary акцент: выделяет то, что отличается от основного, не споря с главным действием. Им же окрашены посещённые ссылки и фон кода.
Три акцента дают иерархию: главное — primary, частое — secondary, особенное — tertiary.
Иллюстрация показывает, где в интерфейсе стоит роль primary и её пара on-primary:

Статусные роли
- Info — информационное сообщение.
- Success — успешный результат.
- Warning — предупреждение, требующее внимания.
- Error — ошибка или опасное действие.
Статусные роли устроены по той же схеме, что акцентные (Система: роль, on-роль, контейнер). Они
соответствуют значениям настройки status у компонентов (info, success,
warning, error; см. Настройки: общий язык компонентов). Значение neutral статуса берёт нейтральное
семейство --sf-neutral, --sf-on-neutral, --sf-neutral-container.
Статус — это смысл, а не украшение. Ошибка обязательно несёт свою роль целиком: красная граница, красный текст сообщения и красная иконка. Иконка ошибки нейтрального серого цвета — дефект, и контракт это проверяет.
Иллюстрации показывают статусные роли в интерфейсе: насыщенную роль, её контейнер и цветную границу.



Поверхности и содержимое на них
Поверхность (surface) — нейтральный фон страницы, областей и панелей.
| Роль | Работа |
|---|---|
--sf-surface-0 … --sf-surface-5 |
Ступени нейтрального фона. surface-0 — белый в светлой теме и самый тёмный тон в тёмной |
--sf-surface-container (+ -hover, -active) |
Полупрозрачная нейтральная плашка: залитое поле, тональная кнопка без акцента |
--sf-surface-inverse |
Инверсная поверхность: тёмная в светлой теме, светлая в тёмной (подсказки, тосты) |
--sf-surface-overlay |
Вуаль сцены — затемнение под модальным окном |
--sf-on-surface |
Основной текст и иконки |
--sf-on-surface-hover / -active |
Основной текст при наведении / нажатии |
--sf-on-surface-variant |
Вспомогательный текст и служебные иконки |
--sf-on-surface-container--variant |
Вспомогательный текст на плашке --sf-surface-container. Компоненты с плашкой подставляют её сами |
--sf-on-surface-muted |
Ещё более слабая ступень — только для отключённого и декоративного |
--sf-on-surface-inverse |
Текст на инверсной поверхности |
Роли с окончанием -fixed (--sf-on-surface-fixed,
--sf-surface-inverse-fixed, --sf-on-surface-inverse-fixed) не меняются с темой. Они нужны элементу, который
сознательно выглядит одинаково в обеих темах.
Ступени поверхности выполняют две разные задачи.
Зона экрана выбирается при вёрстке и не меняется. Правило: чем ближе зона к
основному содержимому страницы, тем ближе её поверхность к surface-0.
| Зона | Поверхность |
|---|---|
| Рабочая область | surface-0 |
| Вспомогательная панель: список, боковая колонка | surface-1 |
| Служебная оболочка: панель значков, рельс | surface-2 |
Внутри зоны вложенность работает как обычно: карточка в рабочей области стоит на ступень дальше своей зоны. Не рекомендуется опускаться глубже двух ступеней от зоны: приглушённый текст перестаёт проходить по контрасту.
Пример показывает три зоны и поднятую над ними панель:
В тёмной теме порядок зон сохраняется: оболочка остаётся самой глубокой, рабочая область — самой светлой.
Высота меняется по состоянию: меню всплыло, модальное окно открылось. Для неё
есть отдельная пара токенов (Высота: поверхность и тень). Ступени surface-3 … surface-5 зонам не
назначаются: они нужны высоте в тёмной теме.

Содержимое: три силы текста. on-surface — то, что читают; variant —
то, что поясняет; muted — то, что отключено или чисто декоративно.
muted даёт около 3,2 : 1 в светлой теме и 2,9 : 1 в тёмной — этого мало и
для текста, и для значимой графики, поэтому для подписей, подсказок,
плейсхолдеров и иконок его использовать нельзя; это проверяет контракт.
Утилиты цвета для muted нет: для текста берут color-on-surface и
color-on-surface-variant (Цвет текста).
Приглушённый текст на плашке. Плашка --sf-surface-container
полупрозрачная и в тёмной теме светлее фона под ней, поэтому обычный
вспомогательный текст на ней читается хуже порога 4,5 : 1. Для текста на
плашке есть своя роль — --sf-on-surface-container--variant. Компоненты,
которые кладут плашку под содержимое (тег, аватар с инициалами, уведомление,
аккордеон, поле ввода, клавиша, тост и другие), подставляют её сами: внутри
них var(--sf-on-surface-variant) уже даёт нужное значение. Утилита
bg-surface-container подставляет роль так же, как класс высоты
elevation-N: вспомогательный текст внутри элемента с этим классом берёт её
сам. В своём CSS с плашкой переопределите роль так же, как для поднятой
поверхности:
.project-chip {
background: var(--sf-surface-container);
--sf-on-surface-variant: var(--sf-on-surface-container--variant);
}
Интерактивные роли
Состояние элемента выражается ролью. Способ зависит от того, есть ли у элемента собственная заливка.
У элемента есть заливка — состояние меняет тон заливки:
--sf-primary → --sf-primary-hover → --sf-primary-active; у контейнера —
-container-hover, -container-active.
У элемента нет заливки (пункт меню, строка таблицы, контурная кнопка) — состояние кладёт поверх поверхности полупрозрачный слой:
| Роль | Состояние |
|---|---|
--sf-{роль}-transparent-hover |
Наведение |
--sf-{роль}-transparent-select |
Выбранный элемент в наборе |
--sf-{роль}-transparent-active |
Нажатие |
Полупрозрачный слой не зависит от поверхности под ним и поэтому правилен на
любой. Для нейтральных элементов то же даёт семейство
--sf-surface-transparent-*.
Границы
У нейтральных границ две роли, и у каждой своя задача.
--sf-outline— граница того, что пользователь должен найти: поле, многострочное поле, выпадающий список, флажок, радио, переключатель, контурная кнопка. Она обязана держать 3 : 1 к поверхности (см. Контраст).--sf-outline-variant— край области и линии внутри неё: панель, карточка, таблица, строка. Такие линии делят пространство, их не ищут. Роль тихая (около 1,3 : 1 и 1,9 : 1) и для границы контрола не подходит.
Состояние границы контрола выражается цветом, а не более тёмным серым:
наведение берёт --sf-primary, фокус — кольцо --sf-focus (см. Фокус),
ошибка — --sf-error, отключённость — --sf-outline-disable. Пример
показывает, как это сделано у поля ввода:
--sf-input-field--border-color: var(--sf-outline); /* в покое */
--sf-input-field--border-color: var(--sf-primary); /* наведение */
--sf-input-field--border-color: var(--sf-error); /* ошибка */
--sf-input-field--border-color: var(--sf-outline-disable); /* отключено */
Цветные границы --sf-outline-{роль} (outline-primary, outline-error и
т. д.) берут тон 50 в светлой теме и 60 в тёмной.
Залитые контролы (тональная кнопка, залитое поле) не имеют границы: их опознают по заливке, постоянной подписи и состоянию.
Граница контрола стоит ровно на пороге 3 : 1. Если продукту нужна более контрастная линия, её задают одной ролью в CSS проекта, и она меняется у всех контролов сразу:
@layer project {
.theme-light,
.theme-dark {
--sf-outline: light-dark(var(--sf-neutral-50), var(--sf-neutral-60));
}
}
Отключённое состояние
| Роль | Работа |
|---|---|
--sf-disable |
Заливка отключённого элемента |
--sf-on-disable |
Текст и иконка отключённого элемента |
--sf-outline-disable |
Граница отключённого элемента |
Переход из активного состояния в отключённое идёт по одной схеме: любая
заливка (primary, primary-container) → disable; любое содержимое
(on-primary, on-primary-container) → on-disable; любая граница →
outline-disable.
Правила:
- Отключённость сильнее включённости. Отмеченный флажок, выбранное радио, включённый переключатель — тоже состояния, и каждое красит элемент в primary. Когда элемент отключён, выигрывает disable, иначе заблокированная отметка выглядит так же, как та, которую можно снять.
--sf-disable— это заливка, а не цвет текста. 12 % достаточно, чтобы заменить фон, и недостаточно для текста. Подпись и знак отключённого элемента берут--sf-on-disable.- Отключённая граница слабее активной, но видна. Контрол без границы теряет форму, а не только доступность.

Требования WCAG к контрасту на отключённые элементы не распространяются, но отключённая подпись во Framework остаётся читаемой (около 3,1 : 1 в светлой теме и 4,1 : 1 в тёмной): иначе у отмеченного заблокированного флажка пропадает сама галочка — скрывается значение, а не только состояние.
Служебные роли
- Link —
--sf-linkи его состояния-hover,-active,-visited. Ссылка берёт тона primary, посещённая — tertiary. - Focus —
--sf-focus, цвет кольца фокуса. Он берёт тона primary:--sf-primary-50в светлой теме и--sf-primary-90в тёмной, поэтому смена палитрыprimaryперекрашивает и кольцо. Кольцо сплошное, не полупрозрачное: индикатору фокуса нужно 3 : 1, а полупрозрачное кольцо этот порог не держит. Толщина, отступ и правила рисования кольца — в Фокус. - Mark —
--sf-mark, выделение фрагмента текста (результат поиска, пометка). Полупрозрачный тон warning. - Code —
--sf-code, фон фрагмента кода. Полупрозрачный тон tertiary.

Цвет иконки: три роли
Иконка читается вместе с текстом рядом. Поэтому её цвет соответствует весу текста, и ролей у неё ровно три:
| Роль | Когда |
|---|---|
--sf-on-surface |
Иконка несёт смысл наравне с текстом: в заголовке, в пункте меню, в кнопке действия |
--sf-on-surface-variant |
Служебная иконка: ручка перетаскивания, «закрыть», «настроить», подсказка, стрелка сортировки |
--sf-on-disable |
Элемент отключён |
Внутри окрашенного контрола иконка берёт цвет его собственного текста:
--sf-on-primary в залитой кнопке, --sf-error в поле с ошибкой. Акцентная
или статусная иконка вне контрола берёт насыщенную роль (--sf-primary,
--sf-error и другие): по таблице ролей это цвет акцентного текста и иконки.
Нельзя:
--sf-on-surface-muted— слишком бледна для значимой графики;--sf-outline,--sf-outline-variant,--sf-outline-disable— это роли границы: тема, перенастроившая границы, сдвинула бы и иконки.
Без особых указаний иконка берёт currentColor — цвет текста вокруг. В
разметке проекта цвет иконки задаётся утилитой цвета на самой иконке или на
предке:
<div class="my-card-actions color-on-surface-variant">…</div>
Правило иконки объявлено в слое sf.base, поэтому утилиты color-* на иконке
работают. Внутри компонентов цвет иконки передаётся внутренней переменной
--sf-icon--color; проект её не задаёт.
Знак бренда и встроенный SVG
Логотип и знак бренда в шапке — не иконка, но одноцветный знак красится по
тем же правилам: роль заливки задают утилиты fill-* и stroke-*
(Цвет заливки) прямо на <svg> или его
частях, например fill-primary для акцентного знака и fill-on-surface для
нейтрального. Так знак меняет цвет вместе с темой.
<a href="/" aria-label="На главную">
<svg class="svg-3 fill-primary" viewBox="0 0 24 24" aria-hidden="true">…</svg>
</a>
Другой способ — fill="currentColor" (или stroke="currentColor") в SVG и
утилита цвета color-* на знаке или на ссылке вокруг него: знак берёт цвет
текста.
Многоцветный логотип сохраняет свои фирменные цвета и в роли не переводится; проверьте его контраст на поверхности в обеих темах. Цвета знаков соцсетей дают утилиты фирменной заливки.
Смотрите также
- Прозрачность — ступени прозрачности ролей;
- Все переменные — значения ролей в обеих темах;
- Контраст — контраст ролей;
- Фокус — кольцо фокуса;
- Настройки: общий язык компонентов — настройки
schemeиstatus.