~/wiki / dostupnost / tsvet-kak-edinstvennyy-signal-pochemu-eto-oshibka

Красный — это ошибка? Не для всех. Почему цвет нельзя использовать как единственный сигнал

Основной чат

Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.

$ cd раздел/ $ join vibe dev
Красный — это ошибка? Не для всех. Почему цвет нельзя использовать как единственный сигнал - обложка

Откройте любую аналитику. Красный график — что-то сломалось. Красная плашка — ошибка. Красная точка — непрочитанное, требующее внимания. Кажется, что это просто здравый смысл: красный = плохо, зелёный = хорошо, и так устроен мир.

А теперь представьте дальтоника, который видит красный и зелёный как два оттенка одного грязно-горчичного. Или китайского пользователя, для которого красный — цвет удачи, праздника и роста акций на бирже. Или человека в тёмной теме при ярком солнце, где ваш «алярм» сливается с фоном. Для них ваш аккуратный визуальный код не работает. А вы об этом даже не узнаете, потому что в метриках это выглядит как «непонятные просадки конверсии в отдельных сегментах».

Цвет — это слабый сигнал. Не плохой, не запрещённый, а именно слабый: его недостаточно, чтобы нести смысл в одиночку. И если вся ваша система состояний построена на «красное — ошибка, зелёное — успех, жёлтое — внимание», у вас не дизайн-система, а допущение, что все видят мир одинаково.

Почему это не «частный случай для 1% пользователей»

Аргумент «дальтоников мало, переживут» звучит регулярно — и он сразу проваливается по нескольким причинам.

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

Во-вторых, цвет ломается не только у дальтоников. Он ломается:

  • на дешёвых матрицах, где красный и оранжевый неотличимы
  • на солнце, когда контраст падает в два раза
  • в тёмной теме, если её делали отдельно и забыли пересчитать семантику
  • в распечатке и скриншоте в чёрно-белом
  • при скриншеринге через сжатие в зуме
  • у уставшего человека в три часа ночи на дежурстве

В-третьих, цвет — это культурный код. Красный в Китае и Индии — позитив. В финансовых интерфейсах в Японии рост рынка часто красный, падение — зелёное, обратное западной норме. Если вы выходите на новые рынки, ваша «очевидная» цветовая семантика становится не очевидной.

И главное: цена ошибки в интерфейсе, где цвет — единственный сигнал, всегда выше, чем кажется. Пропущенная ошибка в форме — это потерянная регистрация. Пропущенный алерт в админке — это инцидент. Пропущенный красный в дашборде хирурга — это уже не про дизайн.

Базовое правило: цвет всегда дублируется

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

Цвет — это усиление сигнала, а не сам сигнал. Если вы убрали цвет и смысл пропал — дизайн сломан.

Это значит, что у любого состояния, которое вы маркируете цветом, должен быть хотя бы один дополнительный носитель смысла:

  • иконка (крест, галочка, восклицательный знак, инфо)
  • текстовая метка («Ошибка», «Готово», «Внимание»)
  • форма или положение (подчёркивание, рамка, отступ, позиция в списке)
  • паттерн или текстура (полоски, штриховка — для графиков и карт)
  • изменение веса или начертания текста

Звучит банально, но в реальных макетах это правило нарушают постоянно — особенно там, где «и так красиво».

Где чаще всего ломается

Несколько типичных мест, на которых я ловлю команды и себя:

  • статусы в таблицах: маленькая цветная точка без подписи — «активен / на паузе / заблокирован» отличить нельзя
  • валидация форм: красная рамка инпута без текста ошибки рядом
  • графики с тремя-четырьмя линиями одного оттенка, отличающимися только цветом
  • теги категорий, где цвет — единственное, что их различает
  • диффы и сравнения «было/стало», где плюс и минус только цветом
  • индикаторы загрузки и онлайн-статуса: зелёная и серая точка без подписи и тултипа

Чеклист на ревью макета

Когда смотрите свой или чужой макет, прогоните его по пунктам:

  • Сделайте скриншот в grayscale. Всё ли ещё понятно?
  • У каждого цветного статуса есть текст или иконка рядом?
  • В графиках линии отличаются не только цветом, но и стилем, маркером или подписью?
  • Ошибки в формах содержат текст ошибки, а не только красную обводку?
  • Ссылки в тексте отличаются от обычного текста не только цветом (подчёркивание, вес)?
  • В тёмной теме семантика сохраняется: «опасное» действие всё ещё читается как опасное?
  • Если интерфейс распечатать — критичная информация не потеряется?

Если хоть один пункт «нет» — это не вкусовщина, это к доработке.

Как встроить это в рабочий процесс, а не в чеклист «когда-нибудь»

Самая частая ошибка — относиться к доступности цвета как к финальной проверке перед релизом. К этому моменту половина решений уже зацементирована: токены утверждены, компоненты собраны, разработчики написали логику на status === 'error' ? 'red' : 'green'. Чинить дорого, никто не хочет.

Поэтому правило простое: цвет проверяется там же, где он появляется. На этапе токенов, на этапе компонента, на этапе экрана. Три точки контроля, а не одна в конце.

На уровне токенов

Когда вы определяете семантические токены — color.status.error, color.status.success, color.status.warning — рядом сразу заводите токены-носители: icon.status.error, label.status.error. Не «цвет ошибки», а «маркер ошибки», у которого цвет — одно из свойств.

Это меняет разговор с разработчиком. Вместо «покрась в красный» — «примени маркер ошибки», и маркер уже знает, что у него есть иконка, цвет и текстовый класс. Дизайн-система перестаёт зависеть от дисциплины каждого конкретного экрана.

На уровне компонента

У каждого статусного компонента — Badge, Tag, Alert, Toast, InputState — должно быть жёсткое правило: цвет не существует отдельно от иконки или подписи. Это закладывается в API компонента, а не в гайдлайн на конфлюенсе.

Простой тест: попробуйте отрендерить компонент со статусом error, но без props icon и label. Если получилось красное пятно — компонент спроектирован плохо. Должно ругаться в типах или хотя бы в сторибуке.

На уровне экрана

Здесь уже задача дизайнера и ревьюера. Перед тем как закинуть макет в дев, прогоните три быстрых режима:

  1. Grayscale — снимает цвет полностью
  2. Симуляция дейтеранопии и протанопии — в Figma это плагины, в браузере DevTools
  3. Уменьшение масштаба до 50% — маленькие цветные точки на статусах исчезают первыми

Если на любом из режимов состояние перестаёт читаться — фиксим до передачи в разработку.

Типичные анти-паттерны, которые я вижу из раза в раз

«Мы добавим иконку потом»

Не добавите. «Потом» — это релиз, поддержка, следующий квартал. Если иконки нет в первой итерации компонента, её не будет никогда, потому что бэклог всегда длиннее воли.

Иконка есть, но она тоже только цветом отличается

Любимое: круглый бейдж со статусом, где для активного — зелёный кружок, для отключённого — серый. Технически иконка есть. Семантически — нет, форма одинаковая. Меняйте форму: точка, кольцо, крестик, пауза.

Тултип вместо подписи

«Наведите курсор — увидите статус». На тач-устройствах тултипа нет. На клавиатурной навигации он часто не открывается. У человека с тремором — не наведётся. Тултип — это дополнение, а не замена видимой метке.

Тёмная тема как «инвертированная светлая»

Красный на светлом фоне и тот же красный на тёмном — это два разных цвета по восприятию. Контраст падает, насыщенность кажется другой, граница между «warning» и «error» размывается. Тёмную тему нужно пересобирать по семантике, а не крутить slider в Figma.

Графики «фирменной палитры»

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

Что спрашивать на ревью

Когда смотрите чужой макет или защищаете свой, держите наготове набор коротких вопросов. Они снимают 80% споров «и так нормально».

  • Что произойдёт, если этот экран открыть в grayscale?
  • Какой второй носитель смысла у этого статуса, кроме цвета?
  • Этот компонент в дизайн-системе или нарисован руками? Если в системе — он гарантирует иконку и подпись?
  • Что увидит пользователь со скриншотом в чате, сжатым джипегом?
  • Как это выглядит в тёмной теме — пересчитывали или просто инвертировали?
  • На графике линии различаются ещё чем-то, кроме оттенка?
  • Если это ошибка валидации — текст ошибки точно есть, или только рамка?

Если автор макета на половину вопросов отвечает «ну, обычно видно» — это не ответ, это допущение.

Короткий итог сегмента

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

Когда команда работает с AI и генеративными интерфейсами

Тема цвета как единственного сигнала становится острее, когда часть UI собирает не человек, а модель. Текстовый промпт «сделай статус ошибки красным» — это ровно то, что выдаст красный div без иконки и без подписи, если в дизайн-системе нет жёсткого контракта. AI копирует поверхность, а не намерение.

Что ломается в AI-флоу

Сценарий из практики: продуктовая команда подключает MCP-сервер к Figma, чтобы агент собирал черновики экранов из компонентов библиотеки. Если компонент Alert принимает variant="error" и сам подставляет иконку и дефолтный label — всё хорошо, агент не может его сломать. Если же иконка и текст — это отдельные слои, которые «обычно докидывает дизайнер», агент про них не вспомнит. На выходе — красная плашка с одним словом, и она уезжает в Storybook как валидный пример.

То же самое с v0, Lovable, Cursor и любым другим генератором интерфейсов. Модель оптимизируется под «выглядит как ошибка», а не под «считывается как ошибка слепым пользователем на солнце».

Как закладывать защиту

  • Делайте icon и label обязательными пропсами статусных компонентов, а не опциональными с дефолтом undefined
  • В описании компонента для AI (props description, JSDoc, MCP-схема) явно пишите: «variant определяет цвет и иконку; label обязателен и не должен дублировать variant»
  • В дизайн-токенах называйте семантически — color.feedback.error, а не color.red.600. Модель, которой скормили токены, перестаёт думать «красный = ошибка» и начинает думать «ошибка = ошибка»
  • На стороне линтера или CI — правило, которое валит сборку, если в коде есть инлайновый color: red или #ff в статусных контекстах

Промпты и ревью генераций

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

Но промпт — не гарантия. Ревьюить генерацию нужно теми же тремя режимами, что и человеческий макет: grayscale, симуляция CVD, уменьшенный масштаб. Если агент сгенерил десять экранов за пять минут, это не значит, что вы сэкономили время — это значит, что у вас десять экранов на ревью.

Как проверять качество системно, а не от случая к случаю

Разовая проверка макета — это гигиена. Системная — это процесс, который ловит регрессии без вашего участия.

Автотесты на доступность

  • axe-core или Pa11y в CI на ключевых страницах: они не поймают «красное без иконки», но поймают контраст, ARIA и отсутствие текста у иконок
  • Скриншот-тесты со встроенным CVD-фильтром: прогоняете критичные экраны через симуляцию и сравниваете с эталоном
  • Visual regression на статусные компоненты в Storybook — отдельная история на каждый variant, включая edge case «label пустой»

Метрики в проде

Если есть аналитика — посмотрите на конкретные сигналы. Сколько пользователей повторно сабмитят форму после ошибки валидации? Если много — возможно, они её не видят. Сколько раз нажимают «отключённую» кнопку? Если нажимают — disabled-состояние читается только цветом. Это не идеальные метрики, но они дешевле, чем юзер-тесты, и часто подсвечивают то же самое.

Ритуал на команде

Раз в спринт или раз в две недели — короткая сессия «accessibility pass» по новым экранам. Не аудит на день, а 30 минут, где пара дизайнер + фронт прогоняют свежие макеты в grayscale и CVD-симуляции. Зафиксированные находки идут не в «когда-нибудь», а в текущий спринт как баги, а не как улучшения.

Как объяснять решение команде, когда давят сроком

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

Язык бизнеса

  • Поддержка: каждый тикет «у меня ничего не сохранилось» (а на самом деле было красное сообщение, которое пользователь не считал) — это деньги саппорта и потерянная конверсия
  • Юридический риск: в ряде юрисдикций доступность — это требование закона, и отсутствие текстового дублирования статусов — конкретное нарушение WCAG, на которое можно получить претензию
  • Скриншоты и шеринг: треть переписки про продукт идёт скриншотами в мессенджерах, часто пожатыми. Если на скриншоте не видно, что было не так, это потерянный контекст для b2b-сделок и для саппорта

Язык команды

С разработчиками работает аргумент стоимости: добавить иконку и label в компонент один раз — это час. Переделывать сорок экранов после аудита через полгода — это спринт. С продактом — аргумент роста: меньше ошибок прохождения воронки = выше конверсия, и это измеримо.

Чего не надо делать

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

Чек-лист перед мержем

  • Каждое статусное состояние имеет минимум два носителя смысла из трёх: цвет, форма/иконка, текст
  • Компоненты дизайн-системы технически не позволяют отрендерить статус без иконки и подписи
  • Прогон в grayscale и CVD-симуляции прошёл — для новых экранов и для регрессий
  • Тёмная тема собрана по семантическим токенам, а не инверсией
  • Графики используют категориальную палитру плюс форму линии/маркер, а не пять оттенков бренда
  • AI-генерации и MCP-флоу ревьюятся теми же критериями, что и ручные макеты
  • В CI есть автоматическая проверка контраста и хотя бы один визуальный regression-тест на статусные компоненты

Если по какому-то пункту ответ «обычно да» — это не ответ. Дисциплина в дизайн-системе — это когда правило выполнено машиной, а не памятью дежурного дизайнера.

Вопросы для ревью макета

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

  • Если выключить цвет полностью, можно ли отличить ошибку от успеха и от нейтрального состояния?
  • Сколько носителей смысла у каждого статуса: один, два, три? Если один — почему?
  • Есть ли у иконки текстовая подпись рядом или хотя бы aria-label, который не повторяет соседний текст слово в слово?
  • Что увидит человек с дейтеранопией на этом графике: пять разных линий или две группы по цвету?
  • Как этот экран выглядит на пожатом скриншоте в мессенджере при 60% яркости на улице?
  • Disabled-кнопка читается как недоступная без подсказки на ховер?
  • В тёмной теме семантика «опасно/успешно» сохраняется или цвета просто инвертированы?
  • Если это AI-сгенерированный или MCP-вытащенный кусок UI — он прошёл те же проверки, что и ручной макет, или его пропустили «потому что выглядит ок»?

Если хотя бы на один вопрос ответ «надо посмотреть» — посмотрите сейчас, а не после релиза.

Анти-паттерны, которые встречаются чаще всего

Это не редкие ошибки начинающих. Это то, что регулярно попадает в прод у зрелых команд, потому что «так быстрее» или «так уже было».

Красная рамка вокруг поля без текста ошибки

Поле подсветилось красным, а что не так — догадайся сам. Email? Пароль? Длина? Формат? Пользователь тыкает наугад, форма снова краснеет. Конверсия формы умирает тихо, в аналитике видно только повторные сабмиты.

Зелёная и красная точка статуса в таблице

Классика админок и дашбордов. «Активен / неактивен», «оплачено / не оплачено», «онлайн / офлайн» — две точки разного цвета, без подписи, без формы, без тултипа. В grayscale таблица превращается в одинаковые серые кружки. Решение — добавить форму (заполненный круг vs контур) или короткий лейбл рядом.

Сообщение «успех», окрашенное в красный «по фирстилю»

Бывает, когда бренд агрессивно красный и дизайнер решает «использовать брендовый цвет везде, включая статусы». В итоге успешный платёж выглядит как ошибка. Брендовый цвет не должен пересекаться с семантическими — это разные слои системы.

Светофор из трёх близких оттенков оранжевого

«Низкий / средний / высокий риск» тремя оттенками одного цвета. Различимо у дизайнера на калиброванном мониторе, неразличимо у пользователя на офисном Dell с заводскими настройками. Нужна форма, число или подпись.

Ссылки, отличающиеся от текста только цветом

Особенно в плотных таблицах и в письмах. Подчёркивание — не атавизм, это второй носитель смысла. Убирать его можно только если есть другой явный признак кликабельности (иконка, явный hover, контейнер кнопки).

«Исправим в следующем спринте»

Самый дорогой анти-паттерн. Сорок экранов с цветом-как-единственным-сигналом — это не сорок мелких багов, это системная дыра в дизайн-системе. Чинится в корне (в компоненте), а не на каждом экране отдельно.

Короткий итог

Цвет — это усилитель, а не носитель. Он подсвечивает смысл, который уже выражен формой, иконкой и текстом. Как только цвет остаётся единственным каналом — интерфейс ломается для дальтоников, для человека на солнце, для пожатого скриншота, для печати, для тёмной темы, собранной через инверсию.

Правило, которое экономит часы споров: на каждый статус — минимум два носителя смысла из трёх. Цвет, форма, текст. Один — это всегда мало, даже если кажется, что «и так очевидно».

Дальше работает не вкус, а дисциплина. Компонент дизайн-системы, который физически не даёт собрать статус без иконки и подписи. Прогон в grayscale и CVD как часть ревью, а не как разовый аудит. Автотесты на контраст в CI. Тридцать секунд разговора со скриншотом в grayscale вместо часовой презентации про инклюзию.

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

$ cd ../ ← назад к Доступность