WCAG: скучная аббревиатура которая защитит вас от судебных исков
Основной чат
Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.
Откройте свой продукт и попробуйте дойти до целевого действия, не используя мышь. Только Tab, Enter, стрелки. Если через минуту вы материтесь — поздравляю, у вас типичный «современный» интерфейс. И потенциальный иск в комплекте.
WCAG воспринимают как занудный документ для государственных сайтов и больниц. На практике это единственный международный стандарт, на который суды, регуляторы и крупные заказчики ссылаются, когда решают: ваш интерфейс дискриминирует пользователей или нет. В США иски по ADA за недоступные сайты идут тысячами в год. В ЕС с 2025 действует European Accessibility Act, и он распространяется не только на госсектор, но и на коммерцию, банки, e-commerce, билеты, e-books. В России про это вспоминают реже, но как только вы делаете продукт для зарубежного рынка или для крупного B2B-клиента с compliance-отделом — WCAG прилетает в требования сам.
И тут начинается боль. Дизайнер узнаёт про доступность за неделю до релиза, фронт прикручивает aria-label по всем кнопкам подряд, продакт говорит «ну норм, давайте катить». Через полгода приходит письмо от юристов клиента или скриншот из Axe с 400 ошибками. Дешевле было сделать сразу.
Что такое WCAG на самом деле
WCAG — это не «закон». Это рекомендации W3C, на которые ссылаются законы. Сам по себе он вас ни к чему не обязывает, но его требования вшиты в ADA (США), EAA (ЕС), AODA (Канада, Онтарио), в госзакупки почти везде и в договоры крупных корпораций.
Структура простая, и её полезно держать в голове:
- Четыре принципа (POUR): Perceivable, Operable, Understandable, Robust. Воспринимаемо, управляемо, понятно, устойчиво.
- Уровни соответствия: A (минимум, без него вообще нельзя), AA (рабочий стандарт, на него ссылается большинство законов), AAA (для критичных сценариев — медицина, госуслуги).
- Версии: 2.1 — то, что сейчас требуют чаще всего. 2.2 — текущая актуальная, добавила требования к focus, drag-and-drop, целям нажатия. 3.0 — в разработке, готовиться рано, но следить стоит.
Целевой уровень для коммерческого продукта почти всегда AA по 2.1 или 2.2. Не A — он слишком минимален. Не AAA — он часто конфликтует с реальным дизайном.
Кому это вообще нужно — и почему это не «слепые»
Главный анти-паттерн в голове команды: «доступность = скринридеры = слепые пользователи, их у нас 0.1%». Это удобная неправда.
WCAG защищает гораздо более широкую группу:
- Люди со слабым зрением, дальтонизмом, возрастной потерей чёткости — это десятки процентов аудитории после 40.
- Люди с моторными нарушениями, тремором, временной травмой руки — кто угодно с гипсом.
- Когнитивные особенности: дислексия, СДВГ, усталость, не родной язык интерфейса.
- Ситуативные ограничения: яркое солнце на экране, шумное метро, одна рука занята ребёнком, медленный интернет.
Последний пункт — тот, на который продакты реагируют. Доступный интерфейс — это интерфейс, который работает в плохих условиях. А плохие условия у пользователя бывают всегда.
Вопросы для ревью продукта
- Когда последний раз кто-то в команде проходил ключевой флоу с клавиатуры?
- Знаете ли вы, какой у вас контраст основного текста и фона — числом, а не «вроде нормально»?
- Если выключить все цвета и оставить grayscale, остаются ли понятны статусы, ошибки, активные элементы?
- Что произойдёт, если пользователь увеличит шрифт в браузере до 200%?
Если на половину вопросов ответ «не знаю» — у вас не проблема с WCAG, у вас проблема с тем, что доступность не встроена в процесс.
Контраст: самая частая и самая дешёвая ошибка
Это первое, за что цепляются автоматические сканеры и юристы. И первое, что ломают дизайнеры в погоне за «воздушностью».
Базовые цифры AA, которые стоит выучить наизусть:
- Обычный текст: контраст не менее 4.5:1 к фону.
- Крупный текст (от 18pt обычного или 14pt жирного): 3:1.
- Иконки, контролы, границы инпутов, состояния focus: 3:1 к соседнему фону.
Светло-серый плейсхолдер на белом, бледно-голубая ссылка, тонкая граница инпута цвета #E0E0E0 — это всё классические провалы. На макете в Figma выглядит элегантно, на ноутбуке в кафе днём — не читается вообще.
Чеклист по контрасту
- У основного body-текста контраст ≥ 4.5:1 проверен числом, не на глаз.
- Плейсхолдеры в инпутах не используются вместо лейблов и сами по себе проходят 4.5:1, либо лейбл всегда виден отдельно.
- Границы полей ввода и чекбоксов имеют контраст ≥ 3:1 с фоном формы.
- Состояние focus видно на всех интерактивных элементах и тоже проходит 3:1.
- Disabled-состояния не обязаны проходить контраст, но не должны выглядеть как enabled.
- В тёмной теме контраст проверен отдельно — это не то же самое, что инверсия светлой.
Анти-паттерн: дизайн-система с одной палитрой «текст / текст secondary / текст tertiary», где tertiary имеет контраст 2.8:1. Он попадёт в подсказки, метаданные, таймстампы — и положит весь продукт по AA. Лечится один раз на уровне токенов, потом не возвращается.
Короткий итог сегмента: WCAG — это не благотворительность и не галочка для госсектора, это юридический и продуктовый стандарт, который проще встроить в дизайн-систему сейчас, чем переделывать продукт под аудит потом. Дальше разберём клавиатурную навигацию, формы, медиа и то, как встроить проверку в рабочий процесс, чтобы доступность не была авралом перед релизом.
Клавиатурная навигация: тест, который проходит почти никто
Возьмите свой продукт, отложите мышь и попробуйте пройти ключевой сценарий клавишей Tab, Shift+Tab, Enter, Space и стрелками. Большинство команд впервые делают это на ревью с тестировщиком и испытывают неприятный шок.
Что обычно ломается:
- Кастомные дропдауны и комбобоксы, собранные из
div, не реагируют на стрелки и Esc. - Модалки не ловят фокус внутрь, и Tab уезжает на фон под оверлей.
- После закрытия попапа фокус улетает в начало страницы вместо того, чтобы вернуться на кнопку, которая попап открыла.
- На картинках-ссылках фокус есть, но визуально не виден: дизайнер убрал
outlineради эстетики и ничего не нарисовал взамен.
Чеклист клавиатурного прохода
- Все интерактивные элементы достижимы Tab’ом в логичном порядке (слева направо, сверху вниз).
- Видимый focus есть всегда — и он не совпадает с hover, чтобы не путать состояния.
- Модалки и поповеры ловят фокус, возвращают его обратно, закрываются по Esc.
- Кастомные контролы (тоггл, селект, тэбы) работают по ожиданиям браузерных аналогов.
- Skip-ссылка «к основному контенту» есть на страницах с тяжёлым шапочным меню.
Если у вас в дизайн-системе нет токена и спецификации focus-кольца — это первая дыра, через которую ускользает половина WCAG-баллов.
Формы: место, где доступность ломается дороже всего
Форма — это контракт с пользователем. Если он не понял, что не так, он уходит и не возвращается. WCAG здесь совпадает с базовым UX.
Анти-паттерны, которые встречаются практически в каждой второй форме:
- Плейсхолдер вместо лейбла. Пользователь начал вводить — подсказка пропала, контекст потерян.
- Ошибка передана только цветом: красная рамка без текста и без иконки. Дальтоник и скринридер её не получат.
- Сообщение об ошибке живёт визуально рядом с полем, но в разметке оторвано от него — скринридер прочитает «инпут» и тишину.
- Required-поля отмечены только звёздочкой без объяснения, что она значит.
- Автофокус при загрузке страницы прыгает в середину экрана и ломает ориентацию.
Что закладывать в макет формы
- Видимый лейбл над полем, всегда.
- Состояния: default, hover, focus, filled, error, disabled — нарисованы как отдельные элементы дизайн-системы.
- Текст ошибки рядом, конкретный («введите email в формате name@domain»), не «ошибка».
- Дублирование смысла: цвет + иконка + текст. Любые два из трёх минимум.
- Подсказки и описания привязаны к полю через спецификацию для разработчика, а не «висят рядом».
Медиа, движение и автоплей
Картинки без alt, видео без субтитров, анимация, которая не останавливается — это три классические претензии в любом аудите.
Правила, которые проще держать на уровне процесса, чем потом чинить:
- У каждой содержательной картинки — текстовое описание. У декоративной — пустой alt, чтобы скринридер её пропустил.
- Видео с речью — субтитры. Не «автоген на YouTube», а вычитанные.
- Анимация дольше 5 секунд и любые мигания — с возможностью отключить, и уважением к
prefers-reduced-motion. - Карусели, которые сами перелистываются — почти всегда плохая идея. Если без них никак, нужна явная пауза.
Как встроить это в рабочий процесс
Главная ошибка — отдавать доступность одному «ответственному за a11y» под конец спринта. Это не работает: к моменту аудита макеты уже свёрстаны и переделывать дорого.
Что работает на практике:
На уровне дизайн-системы
- Контраст всех текстовых токенов проверен и подписан в Figma.
- Focus-стиль — отдельный компонент или эффект, не «нарисуем в коде».
- Размер целей нажатия минимум 24×24 (а лучше 44×44 для мобильного) заложен в кнопки, иконки, чекбоксы.
- Тёмная тема проверена отдельно, а не получена инверсией.
На уровне макета
- Дизайнер прикладывает к ключевым экранам tab-порядок и состояния focus.
- Сценарии ошибок и пустых состояний нарисованы вместе с основным флоу, а не «по остаточному».
- Плагин-чекер контраста запущен до передачи в разработку, а не после.
На уровне команды
- В definition of done у фичи есть пункт «проходится с клавиатуры и проверена в скринридере хотя бы поверхностно».
- Автоматический сканер (axe, Lighthouse, аналог) подключён в CI и не даёт деплоить регрессии.
- Раз в квартал команда садится и проходит реальный сценарий вместе с человеком, который пользуется ассистивными технологиями. Один такой час меняет приоритеты сильнее, чем десять отчётов.
Вопросы для ревью макета
- Каждое состояние интерактивного элемента нарисовано отдельно?
- У форм есть макеты ошибок, не только «успешный путь»?
- Текстовые токены подписаны контрастом к фону, на котором используются?
- Если из макета убрать все цвета, остаются ли понятны иерархия и статусы?
- Есть ли в макете focus-стиль или это «придумает разработчик»?
Короткий итог сегмента: доступность не делается героическим аудитом перед релизом, она делается по чуть-чуть в каждом макете, токене и компоненте. Дальше посмотрим на инструменты проверки, автоматизацию, AI-помощников и то, где их обещания расходятся с реальностью.
Инструменты проверки: что реально ловит проблемы
Автоматика находит примерно треть нарушений WCAG. Это много — но это не «доступность одной кнопкой». Всё, что связано со смыслом (адекватный alt, понятная ошибка, логичный порядок чтения), машина не оценит.
Грубая иерархия по тому, что чем ловится:
- Линтеры и сканеры (axe, Lighthouse, Pa11y). Контраст, отсутствующий alt, дубли id, поля без label, нарушения структуры заголовков. Быстро, дёшево, в CI.
- Плагины в Figma. Контраст токенов, проверка пар «текст на фоне», симуляция дальтонизма. Полезно на этапе макета, до того как код вообще написан.
- Ручная проверка с клавиатуры. Tab, Shift+Tab, Enter, Esc, стрелки. Если фокус теряется, прыгает в невидимую область или застревает в модалке — это видно за минуту.
- Скринридер. VoiceOver на Mac/iOS, NVDA на Windows, TalkBack на Android. Один проход по флоу выявляет почти все смысловые проблемы: безымянные кнопки, оторванные ошибки, бесконечные «изображение, изображение, изображение».
Если выбирать одно действие, которое даёт максимум — это десять минут с включённым скринридером на своём же продукте. Эффект отрезвляющий.
Анти-паттерн: «у нас Lighthouse 100, мы доступны»
Lighthouse 100 означает, что вы не провалили автоматические тесты. Это всё. Кнопка с текстом «Подробнее» без контекста, форма, где ошибка не связана с полем семантически, модалка, из которой нельзя выйти Esc — всё это спокойно проходит сканер.
AI-ассистенты и доступность: где помогают, где врут
LLM и плагины в Figma/VS Code уже неплохо генерируют alt, переписывают сообщения об ошибках, предлагают aria-атрибуты. Но это инструмент усиления, а не замены ревью.
Что разумно делегировать AI
- Черновик alt-текстов для библиотеки иллюстраций — потом дизайнер или редактор проходит и правит.
- Переписывание системных ошибок в человеческий язык («введите email в формате name@domain» вместо «invalid input»).
- Объяснение, какой ARIA-паттерн подходит под конкретный кастомный компонент, со ссылкой на спецификацию.
- Первичный анализ макета: «найди потенциальные проблемы доступности на этом экране» — как дополнительная пара глаз.
Где AI стабильно подводит
- Галлюцинации с ARIA. Модель уверенно предлагает
aria-*, которых не существует, или комбинации, которые ломают семантику. Любую рекомендацию по ARIA проверять по спецификации, а не верить на слово. - Контекст продукта. AI не знает, что у вас «Сохранить» в этом флоу — это на самом деле «Отправить заявку юристу». Alt и лейблы без контекста получаются обобщёнными и бесполезными.
- Порядок чтения и фокуса. Модель видит макет как картинку, а не как дерево. Tab-порядок и логику навигации она угадывает, и часто мимо.
- MCP-интеграции с Figma. Когда агент сам правит макет «чтобы был доступнее», он легко ломает токены и состояния, которые вы выстраивали. Изменения от AI ревьюить так же строго, как PR от джуна.
Рабочая модель — AI готовит варианты, человек принимает решение. Не наоборот.
Как объяснять решение команде
Доступность редко режется потому, что «все против». Чаще она режется потому, что её ценность не сформулирована на языке, который слышат продакт и бизнес.
Что работает в разговоре:
- Юридический риск. Один публичный иск или предписание регулятора стоит дороже, чем год работы над a11y. В B2B-тендерах VPAT/accessibility statement всё чаще обязательный документ — без него просто не пускают.
- Размер аудитории. Постоянные нарушения зрения, моторики, слуха, плюс ситуативные (яркое солнце, сломанная рука, шумное метро) — это не нишевая группа, это значимая доля любой массовой аудитории.
- Качество как побочный эффект. Команды, которые держат планку по доступности, обычно делают и более понятные формы, и более стабильные компоненты. Это видно на ревью и в багах от поддержки.
- Дешевле в начале. Контраст токена правится за минуту в дизайн-системе и за неделю — после редизайна на проде.
Вопросы, которые стоит задать на ревью фичи
- Что произойдёт с этим экраном, если пользователь не видит цвет?
- Как этот флоу проходится только с клавиатуры?
- Что прочитает скринридер на главной кнопке?
- Есть ли у каждого состояния (загрузка, ошибка, пусто) понятный текст, а не только иконка?
- Если фичу выкатить завтра, что нам напишут в поддержку первым?
Короткий итог: автоматика ловит грубое, AI ускоряет рутину, но смысловые решения и аргументацию команда несёт сама. Дальше — как всё это сложить в устойчивый процесс и что брать в работу первым, если начинать с нуля.
Минимальный чеклист, с которого можно начать завтра
Если у вас сейчас нет вообще никакого процесса по доступности, не надо писать стратегию на квартал. Возьмите этот список и пройдите по нему на одном ключевом флоу — онбординг, оплата, основное действие продукта.
Дизайн-макет
- Контраст текста к фону проверен на всех состояниях, включая hover, disabled, плейсхолдер
- Цвет не единственный носитель смысла (ошибка не только красная, статус не только зелёный кружок)
- Размер тач-таргета на мобильном не меньше комфортного для пальца, между соседними целями есть зазор
- У каждой иконки-кнопки есть текстовая подпись или явный aria-label в спеке
- Указаны состояния фокуса для всех интерактивных элементов, а не только hover
- Формы: каждое поле имеет видимый лейбл, ошибки описаны текстом, а не только цветом рамки
- Модалки и оверлеи: в макете описано, как из них выйти и куда возвращается фокус
Код и сборка
- Страница имеет осмысленный
<title>и язык в<html lang> - Заголовки идут по иерархии, без скачков с h2 на h5
- Изображения, несущие смысл, имеют alt; декоративные — пустой alt
- Кнопка — это
<button>, ссылка — это<a>, не<div onClick> - Форма проходится Tab сверху вниз без сюрпризов, фокус виден всегда
- Esc закрывает модалку, фокус возвращается на элемент-триггер
- Динамические сообщения (тосты, ошибки валидации) объявляются скринридеру через
aria-liveили роль
Ревью и релиз
- В шаблоне PR есть пункт про a11y, даже если просто «проверил клавиатурой»
- Перед релизом фичу один раз прошли скринридером — VoiceOver, NVDA или TalkBack
- У дизайн-системы зафиксированы доступные комбинации токенов, а не только палитра
- В критериях приёмки задачи прописаны клавиатурные сценарии
Анти-паттерны, на которых горят даже зрелые команды
«Сделаем отдельную доступную версию»
Параллельная упрощённая версия сайта живёт ровно до первого редизайна основной. Потом она отстаёт, ломается и становится хуже, чем если бы её не было. Доступность встраивается в основной продукт или не встраивается никак.
Скип-линк, который ведёт в никуда
«Перейти к содержимому» — хорошая идея, если фокус после неё реально попадает в начало контента. Часто ссылка есть, а фокус остаётся в шапке, потому что у целевого блока нет tabindex="-1" и фокус-управления. Лучше не иметь скип-линка, чем иметь нерабочий.
Aria поверх всего
Когда команда узнаёт про ARIA, появляется соблазн обвешать ей каждый компонент. role="button" на кнопке, aria-label поверх видимого текста, который не совпадает с тем, что написано на экране, aria-hidden на интерактивных элементах. Первое правило ARIA — не использовать ARIA, если есть нативный HTML-элемент, который делает то же самое.
Доступность как задача одного человека
«У нас есть Маша, она про a11y». Маша уходит в отпуск — и фичи едут без проверки. Доступность работает только как разделённая ответственность: дизайнер закладывает, разработчик реализует, QA проверяет, продакт не режет.
Тестирование только своей мышкой
Команда смотрит на макет глазами здорового зрячего человека с быстрым интернетом и новым ноутбуком. Любой непривычный контекст — лупа системы, увеличенный шрифт в браузере, навигация только клавиатурой, мобильный в одной руке — открывает слой проблем, которого на ревью не видно.
Вопросы для код-ревью и дизайн-ревью
Эти вопросы стоит вшить в шаблон, чтобы они задавались по умолчанию, а не когда кто-то вспомнил.
На дизайн-ревью
- Где в этом макете состояние фокуса и чем оно отличается от hover?
- Что происходит, если у пользователя системный шрифт +50%?
- Как этот компонент выглядит и звучит в состоянии ошибки, загрузки, пустого результата?
- Если убрать все цвета и оставить серую шкалу, останется ли смысл?
- Что должно быть прочитано вслух при наведении на эту иконку?
На код-ревью
- Можно ли дойти до основного действия только клавиатурой?
- Какой роли соответствует этот кастомный компонент и проверена ли она по спецификации ARIA-паттернов?
- Куда уходит фокус после закрытия модалки, удаления элемента списка, отправки формы?
- Все ли динамические изменения, важные для пользователя, объявлены ассистивным технологиям?
- Есть ли у поля видимая связь с лейблом и сообщением об ошибке через
for/idилиaria-describedby?
Что брать в работу первым, если начинаете с нуля
Порядок, который обычно даёт максимум эффекта при минимуме сопротивления:
- Починить контрасты в дизайн-системе. Это правится централизованно и закрывает целый класс нарушений сразу.
- Привести в порядок фокус: видимый, предсказуемый, не теряющийся в модалках.
- Пройти клавиатурой главный флоу и записать всё, что ломается.
- Включить скринридер на том же флоу. Это и есть момент, когда команда обычно решает, что доступность — это не теория.
- Зашить пункты про a11y в шаблоны задач, PR и определение готовности.
Дальше уже можно говорить про регулярный аудит, обучение, VPAT и интеграцию с CI. Но без первых пяти шагов всё остальное — бумага.
Доступность — это не про идеальное соответствие WCAG до последней буквы. Это про то, что ваш продукт продолжает работать, когда условия пользователя отличаются от условий дизайнера. И про то, что в день, когда придёт юрист или тендер с требованием accessibility statement, у команды есть что показать, а не три недели судорожного латания.