Красный — это ошибка? Не для всех. Почему цвет нельзя использовать как единственный сигнал
Основной чат
Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.
Откройте любую аналитику. Красный график — что-то сломалось. Красная плашка — ошибка. Красная точка — непрочитанное, требующее внимания. Кажется, что это просто здравый смысл: красный = плохо, зелёный = хорошо, и так устроен мир.
А теперь представьте дальтоника, который видит красный и зелёный как два оттенка одного грязно-горчичного. Или китайского пользователя, для которого красный — цвет удачи, праздника и роста акций на бирже. Или человека в тёмной теме при ярком солнце, где ваш «алярм» сливается с фоном. Для них ваш аккуратный визуальный код не работает. А вы об этом даже не узнаете, потому что в метриках это выглядит как «непонятные просадки конверсии в отдельных сегментах».
Цвет — это слабый сигнал. Не плохой, не запрещённый, а именно слабый: его недостаточно, чтобы нести смысл в одиночку. И если вся ваша система состояний построена на «красное — ошибка, зелёное — успех, жёлтое — внимание», у вас не дизайн-система, а допущение, что все видят мир одинаково.
Почему это не «частный случай для 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. Если получилось красное пятно — компонент спроектирован плохо. Должно ругаться в типах или хотя бы в сторибуке.
На уровне экрана
Здесь уже задача дизайнера и ревьюера. Перед тем как закинуть макет в дев, прогоните три быстрых режима:
- Grayscale — снимает цвет полностью
- Симуляция дейтеранопии и протанопии — в Figma это плагины, в браузере DevTools
- Уменьшение масштаба до 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 вместо часовой презентации про инклюзию.
Красное — это не ошибка. Красное плюс крестик плюс «не удалось сохранить» — это ошибка. Разница между этими двумя вариантами и есть граница между интерфейсом, который работает для всех, и интерфейсом, который работает только при хорошем свете.