01

Считайте каждое состояние полной цветовой парой

Начинайте с семантических ролей состояний, а не с одного фирменного образца. У заполненной основной кнопки есть надпись, заливка, возможная граница, значок и окружающая поверхность. Hover и active меняют заливку, а focus добавляет индикатор, соприкасающийся и с контролом, и со страницей. Вторичная или контурная кнопка создаёт другой набор соседних цветов. Запишите каждый передний план, фон и границу. Нельзя заключать, что более тёмный hover проходит только потому, что прошёл default: отношение текста, видимость границы и фокуса пересчитывают для реально отрисованного состояния.

  • Перечислите default, hover, active, focus, disabled, loading и selected, которые компонент действительно отображает.
  • Для каждого варианта запишите надпись, значок, заливку, границу, индикатор фокуса и окружающую поверхность.
  • Считайте primary, secondary, destructive и quiet отдельными контрактами, а не перекрашенным образцом.
  • Сохраняйте нативную семантику button, чтобы клавиатура и доступное имя не зависели от палитры.
02

Измеряйте текст, границу и фокус по их назначению

Текст надписи сравнивают с отрисованной заливкой кнопки. Критерий WCAG 2.2 1.4.3 обычно требует не менее 4,5:1 для обычного текста и 3:1 для крупного согласно определениям и исключениям критерия. Нетекстовый контраст относится к визуальной информации, необходимой для распознавания компонентов и состояний; если эту функцию выполняет заливка или граница, её проверяют относительно соседних цветов по 1.4.11. У индикатора фокуса отдельные требования, и он должен восприниматься в focused-состоянии. Одно отношение не подтверждает все задачи: в каждом сравнении участвуют другие пиксели и смысл.

ЧастьС чем сравнитьВопрос
Надпись или значокОтрисованная заливкаСодержание читается?
Существенная границаСоседняя поверхностьКонтрол распознаётся?
Индикатор фокусаЦвета соприкосновенияКлавиатурный фокус виден?
Смена состоянияПредыдущее и текущее оформлениеОбратная связь воспринимается?
03

Реализуйте состояния без потери фокуса

В примере цвета заданы явно, чтобы каждую пару можно было измерить. Это иллюстрация, а не универсально соответствующая палитра: свойства шрифта, окружающие поверхности, рендеринг браузера и варианты компонента всё равно тестируют. :focus-visible показывает заметный клавиатурный фокус в поддерживающих браузерах, а политика совместимости должна сохранять подходящий фолбэк. Outline смещён от границы, чтобы не сливаться с ней, но в плотном макете он может касаться нескольких фонов. Никогда не удаляйте пользовательский outline без замены, не менее заметной во всех состояниях и условиях обрезки.

css
.button {
  color: #ffffff;
  background: #4338ca;
  border: 2px solid #4338ca;
}

.button:hover { background: #3730a3; }
.button:active { background: #312e81; }
.button:focus-visible {
  outline: 3px solid #6d28d9;
  outline-offset: 3px;
}

.button[disabled] {
  color: #64748b;
  background: #e2e8f0;
  border-color: #cbd5e1;
}
04

Проектируйте hover, active, loading и disabled осознанно

Hover — обратная связь для указателя, он не заменяет клавиатурный focus. Active или pressed может быть кратким, но надпись не должна исчезать во время активации. Loading сохраняет доступное имя и сообщает о прогрессе не только сменой цвета; появление спиннера не должно двигать макет. Для disabled существуют исключения в отдельных критериях контраста, однако чрезмерно бледная кнопка мешает понять доступные действия и причину блокировки отправки. Проверьте, действительно ли контрол нужно отключать, и покажите рядом валидацию или объяснение, если не выполнено предварительное условие.

  • Пересчитывайте контраст надписи после каждой смены заливки: более тёмное не всегда лучше для любого текста.
  • Оставляйте hover для указателя, а focus делайте отдельно видимым для клавиатурной навигации.
  • Сочетайте loading-визуал с программным состоянием и стабильным доступным именем, а не одной анимацией цвета.
  • Используйте disabled только для действительно недоступного действия и объясняйте исправимое условие рядом.
  • Для selected или pressed у переключателя применяйте семантику вроде aria-pressed.
05

Учитывайте alpha, градиенты, значки и вложенные поверхности

У полупрозрачной заливки и границы нет единственного итогового цвета независимо от страницы. Выполните композитинг для каждой допустимой поверхности до расчёта контраста. У градиентной кнопки проверяют значимые точки под надписью и значком, а не только края градиента. Значку, передающему действие, нужны достаточная видимость и доступное имя через видимый текст или другой механизм; декоративный значок не должен создавать повторное объявление. Если кнопка находится в баннере, карточке, диалоге, поверх изображения или в disabled-контейнере, для границы и фокуса используют настоящий соседний цвет. Общий токен действителен лишь в документированных контекстах.

06

Перед выпуском прогоните матрицу компонентов

Отрисуйте каждый вариант кнопки на каждой поддерживаемой поверхности с реалистичными надписями, значками, переносами и локализацией. Навигируйте клавиатурой, указателем, касанием и подходящей вспомогательной технологией. Проверьте focus при обычном и увеличенном масштабе, особенно у края контейнера, где overflow обрезает outline. Включите high contrast или forced-colors и убедитесь, что нативная семантика сохраняет контролы и состояния. Автоматические проверки полезны для детерминированных пар, но градиенты, alpha, динамические фоны, анимация и обрезка требуют просмотра. Храните матрицу рядом с токенами для повторения после изменений.

  • Отрисуйте существующие primary, secondary, quiet, destructive, icon-only и toggle-варианты.
  • Пройдите default, hover, active, focus, loading, disabled, error-adjacent и selected.
  • Проверьте все поверхности, включая карточки, диалоги, баннеры, таблицы и области поверх изображений.
  • Повторяйте контраст и focus после изменений типографики, отступов, границ, теней и общих токенов.
S

Первоисточники

Фактические утверждения статьи проверены по этим опубликованным спецификациям.

  1. W3C WCAG 2.2 — минимальный контраст
  2. W3C WCAG 2.2 — нетекстовый контраст
  3. W3C WCAG 2.2 — внешний вид фокуса (уровень AAA)
  4. W3C WAI-ARIA 1.2 — состояние aria-pressed