Пять инструментов автоматической проверки доступности — и где каждый из них ошибается
Основной чат
Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.
Открой любой сайт, запусти Lighthouse, увидь «Accessibility: 98». Закрой вкладку с чувством выполненного долга. А теперь попробуй пройти этот же сайт с клавиатуры, не трогая мышь. Или включи VoiceOver и послушай, как читается главная форма. С большой вероятностью — там ад, который Lighthouse даже не заметил.
Автоматические чекеры доступности — полезные инструменты. Но они проверяют то, что машина умеет проверить: контрасты, наличие alt, корректность ARIA-атрибутов, валидность разметки. Всё, что связано со смыслом, контекстом и реальным сценарием использования, остаётся за бортом. По разным оценкам, автоматика ловит около трети нарушений WCAG. Остальные две трети — это то, ради чего вообще существует доступность.
Дальше — разбор пяти популярных инструментов: что они делают хорошо, где врут, и в каких ситуациях на их зелёный значок нельзя опираться вообще.
Почему «100/100» — это ловушка, а не цель
Главная проблема не в инструментах. Проблема в том, как их используют команды.
Типичный сценарий: продакт ставит задачу «привести accessibility-score к 95+». Дизайнер и фронтенд правят то, что подсвечивает чекер. Score растёт. Все рады. А реальный пользователь со скринридером по-прежнему не может оформить заказ, потому что в модалке фокус прыгает в случайном порядке, а кнопка «Подтвердить» подписана как «button-primary-2».
Зелёный значок создаёт иллюзию решённой задачи. Это хуже, чем отсутствие проверки, потому что выключает дальнейшее мышление.
Что автоматика в принципе не умеет проверить:
- Имеет ли alt смысл (alt="image" формально валиден)
- Логичен ли порядок чтения и фокуса
- Понятен ли визуальный порядок слепому пользователю
- Работает ли кастомный компонент с клавиатуры
- Не ломается ли интерфейс при зуме 200% и более
- Правильно ли озвучиваются динамические изменения (live regions)
- Достаточен ли контраст текста на градиенте или фото
Если в команде закрепилось «у нас всё ок, Lighthouse зелёный», стоит один раз провести живой проход с клавиатуры на ретро. Эффект отрезвляющий.
axe DevTools: лучший из автоматов — но всё ещё автомат
axe-core от Deque — движок, на котором так или иначе работает половина индустрии (включая встроенную проверку в Lighthouse). Расширение axe DevTools для Chrome — стандарт де-факто для быстрой ручной проверки.
Что он делает хорошо: ловит почти все формальные нарушения WCAG A и AA, даёт чёткие ссылки на правила, показывает конкретный DOM-узел и предлагает фикс. Минимум ложных срабатываний — если axe говорит «нарушение», скорее всего, это правда нарушение.
Где axe ошибается
Контекст ARIA. axe проверит, что у role="dialog" есть aria-labelledby. Но не проверит, что ссылка ведёт на осмысленный заголовок, а не на пустой <span>. Технически — валидно. По факту — пользователь скринридера слышит «диалог», и тишина.
Кастомные компоненты. Самописный дропдаун без единого ARIA-атрибута axe просто проигнорирует — для него это набор div'ов, и придраться не к чему. Парадоксально: чем хуже сделан компонент, тем меньше у axe поводов ругаться.
Порядок и фокус. axe не проходит интерфейс с Tab. Если фокус после открытия модалки остаётся на кнопке под ней — axe этого не увидит.
Как использовать без самообмана
- Прогонять axe на каждом PR — но только как нижнюю планку, а не как финальную проверку
- К каждому компоненту в дизайн-системе писать сценарий ручной клавиатурной проверки
- Раз в спринт — проход критичных флоу со скринридером (VoiceOver на macOS, NVDA на Windows)
- При ревью PR с новыми ARIA-атрибутами — проверять не «есть атрибут», а «что он озвучивает»
Вопросы для код-ревью, которые axe не задаст:
- Куда уходит фокус после закрытия этого попапа?
- Что услышит пользователь, когда нажмёт на эту кнопку?
- Понятен ли смысл иконки без подписи и без alt?
- Если выключить CSS — сохранится ли порядок чтения?
WAVE: визуальный аудит, который усыпляет бдительность
WAVE от WebAIM — расширение, которое прямо поверх страницы рисует иконки ошибок, предупреждений и структурных элементов. Удобно для быстрого обзора: видно, где заголовки, где landmarks, где проблемные места.
Главное преимущество — наглядность. Можно за минуту понять структуру страницы глазами, не лазая в DevTools. Хорошо подходит для демо заказчику или для обучения новых членов команды: «смотри, вот так выглядит страница без правильной семантики».
Где WAVE подводит
Инструмент сильно полагается на иконки «alerts» — жёлтые предупреждения, которые не являются ошибками, но требуют внимания человека. На практике их игнорируют: «жёлтое — не красное, поехали дальше». А именно в жёлтом сидят самые интересные находки: подозрительные alt, пустые ссылки, дублирующиеся заголовки.
Ещё одна слабость — SPA. WAVE проверяет то, что отрендерено в момент запуска. Динамически подгружаемый контент, модалки, состояния после взаимодействия — всё это в отчёт не попадает. На статичном лендинге работает прекрасно, на сложном приложении показывает половину картины.
И отдельная боль — контраст. WAVE проверяет цвет текста и цвет фона как два значения. Текст на фотографии, на градиенте, на полупрозрачной подложке — слепая зона.
Короткий итог по первым двум инструментам: axe и WAVE решают разные задачи. axe — для CI и формальной проверки правил, WAVE — для быстрого визуального осмотра структуры. Ни один не заменяет ручной проход с клавиатуры и скринридером. И ни один не отвечает на главный вопрос — а понятен ли интерфейс человеку, который видит его не так, как мы.
Lighthouse: удобно, быстро, поверхностно
Lighthouse встроен в Chrome DevTools и в любой нормальный CI. Запустил — получил красивый score из 100 баллов с зелёной плашкой. И в этом главная проблема: команда смотрит на цифру, а не на отчёт.
Под капотом у Lighthouse — урезанная версия axe-core плюс несколько собственных проверок. Урезанная — ключевое слово. Часть правил axe в Lighthouse выключена, часть упрощена. Поэтому ситуация «Lighthouse: 100, axe DevTools: 12 нарушений» — обычное дело, а не аномалия.
Где Lighthouse ошибается
Score-driven разработка. Зелёный кружок становится целью. Команда правит ровно то, что мешает добить до 100, и не трогает то, что Lighthouse в принципе не умеет проверять. Это хуже, чем не проверять вообще, потому что создаёт ложную уверенность.
Только верхний уровень страницы. Lighthouse прогоняет аудит на том DOM, который видит при загрузке. Спрятанные за табами секции, контент за display: none, состояния после клика — пролетают мимо.
Контраст по букве правила. Берёт computed style и считает соотношение. Текст поверх картинки, тени, blur-фон, состояния :hover и :focus — слепые зоны, как и у WAVE.
Как встроить без вреда
- Lighthouse — в CI как нижний порог: «не ниже 90 по accessibility» вместо «должно быть 100»
- Не показывать score в дашбордах руководству как KPI доступности — это убивает смысл
- К каждому PR с UI-изменениями — отдельный прогон axe, а не только Lighthouse
- Раз в квартал — сверка списка проверяемых правил Lighthouse с актуальным axe-core, чтобы понимать, что именно не проверяется
Accessibility Insights: ближе всех к ручной проверке
Инструмент от Microsoft, построенный на том же axe-core, но с одним важным отличием — режимом FastPass и гайдами по ассистированным ручным проверкам. То есть кроме автоматики, он подсказывает, что именно надо потыкать руками, и куда смотреть.
Tab Stops — визуализирует порядок фокуса прямо на странице. Стрелочки, номера, видно где фокус прыгает не туда. Это уже не «автомат сказал ок», это инструмент, который помогает дизайнеру и разработчику глазами увидеть проблему.
Где Accessibility Insights ошибается
Кривая входа. Чтобы получить от инструмента пользу, его нужно изучить. Команды, которые «просто кликают audit», получают от него ровно то же, что от axe — не больше. Tab Stops, Assessment, Needs Review — про эти режимы половина пользователей не знает.
Assessment превращается в формальность. Полная проверка по WCAG занимает часы, и в реальных спринтах её гоняют не на каждую фичу, а раз в релиз. К моменту, когда находишь проблему, фича уже в проде.
Tab Stops не отвечает на «почему». Показывает, что фокус прыгает странно. Не показывает, как починить — это уже к разработчику и к компонентной архитектуре.
Сценарий для дизайн-команды
- При макете нового компонента — сразу рисуем диаграмму фокуса: куда заходит Tab, куда уходит Shift+Tab, что делает Esc
- На ревью прототипа в браузере — Tab Stops включён, проходим флоу глазами, скриним проблемные места
- Найденные проблемы — не в общий бэклог, а в карточку компонента в дизайн-системе, чтобы фикс жил на уровне системы, а не отдельных экранов
Stark в Figma: проверка до того, как поздно что-то менять
Stark — плагин для Figma (и Sketch, и браузера), который ловит проблемы доступности на этапе макета. Контраст, симуляция дальтонизма, проверка размеров touch-target, генерация alt-описаний. Главное достоинство — он работает там, где дизайнер реально живёт, а не отдельным шагом в конце.
Где Stark ошибается
Макет — не интерфейс. Stark проверяет контраст текстового слоя на фоновом слое. В живом продукте этот текст окажется на скролле над картинкой, в тёмной теме, в состоянии disabled — Stark эти контексты не видит, потому что их нет в макете.
Симуляция — не опыт. Прогон через симулятор дейтеранопии полезен, но это всё ещё взгляд зрячего человека через фильтр. Реальный пользователь с нарушением цветовосприятия живёт с ним всю жизнь и компенсирует иначе, чем мы предполагаем.
AI-описания alt. Удобная фича, которая генерирует подпись по изображению. И ровно та же ловушка, что с любым AI: дизайнер вставляет сгенерированный текст не глядя, и в проде у иконки «корзина» появляется alt «изображение чёрного значка».
Чеклист дизайнера до передачи макета в разработку
- Контраст проверен для всех состояний: default, hover, focus, disabled, error
- Состояние focus нарисовано явно, а не «оставим браузерное»
- Touch-target не меньше 44×44 для всех интерактивных элементов на мобайле
- Иконки без подписи имеют текстовое описание в спеке компонента
- Прогон макета через симулятор дальтонизма — смысл сохраняется без цвета?
- Если в макете есть тёмная тема — контраст проверен и в ней
Вопросы для дизайн-ревью
- Что увидит пользователь, который не различает красный и зелёный, на этой форме с валидацией?
- Если убрать цвет совсем — где сейчас сфокусирован пользователь?
- Этот серый плейсхолдер — он точно проходит контраст, или мы себя обманываем?
- Состояние ошибки отличается от обычного только цветом рамки?
Как сложить это в рабочий процесс
Пять инструментов — это не пять чек-боксов в DoD. Это разные точки контроля на разных этапах.
- В Figma — Stark, до того как макет ушёл в разработку
- В PR — axe в CI как обязательный гейт, Lighthouse как мягкий порог
- На ручной проверке фичи — Accessibility Insights с Tab Stops, WAVE для быстрого обзора структуры
- Раз в релиз — проход живым человеком с клавиатурой и скринридером по критичным флоу
Главная ошибка, которую делают команды — выбирают один инструмент и считают, что закрыли вопрос. Автоматика ловит формальные нарушения, не больше. Всё, что связано со смыслом — куда уходит фокус, что слышит скринридер, понятна ли иконка — остаётся ручной работой. И эту работу нужно встраивать в процесс так же системно, как мы встраиваем линтер.
Что делать с AI-генерацией компонентов
Отдельная история — когда часть UI собирается не руками, а через AI-ассистента: Figma Make, v0, Cursor с MCP до Figma, генерация компонентов по описанию. Доступность в таких пайплайнах ломается тихо и одинаково.
Типовые провалы AI-генерации
- Кнопка нарисована как
<div>с обработчиком клика — визуально неотличимо, для скринридера не существует - Модалка без
role="dialog", без ловушки фокуса, закрывается только крестиком мышью - Форма без
<label>, плейсхолдер вместо подписи — потому что в макете «так короче» - Иконка-кнопка без
aria-label— модель сгенерировала SVG и забыла про текстовое имя - Контраст «как в дизайне» — но дизайн был светлой темой, а сгенерировали и тёмную автоматически
Что встроить в процесс, если AI участвует в коде
- Промпт на генерацию компонента содержит требования к доступности явно: семантические теги, состояния focus, ARIA-роли там, где они нужны
- Любой AI-сгенерированный компонент проходит axe и ручной прогон по Tab перед тем как попасть в дизайн-систему
- Запрет на «AI пишет alt и aria-label» без ревью — это та же ловушка, что у Stark, только в коде
- В компонентной библиотеке доступность зафиксирована как часть API: если у
IconButtonнетlabelв пропсах, оно не собирается
Сценарии, которые ловятся хуже всего
Автоматика и плагины ловят статичный DOM в одном состоянии. Всё, что динамическое или контекстное, требует осознанного теста.
Чек на скрытые провалы
- Тосты и снэкбары — анонсируются ли скринридером, не исчезают ли быстрее, чем их успевают услышать
- Модалки — возвращается ли фокус на кнопку-инициатор после закрытия
- Бесконечный скролл — есть ли альтернатива для клавиатуры, не теряется ли позиция при возврате
- Кастомные дропдауны и комбобоксы — стрелки, Enter, Esc, Home/End работают по ожиданию
- Анимации — есть ли уважение к
prefers-reduced-motion, не моргает ли что-то быстрее трёх раз в секунду - Тёмная тема — это не «инверсия светлой», контраст и фокус-стили проверены отдельно
- Состояния загрузки — что слышит скринридер, пока крутится спиннер
Анти-паттерны, которые проходят все автотесты
- Кнопка с
aria-label="кнопка"— формально валидно, по смыслу мусор alt=""у иллюстрации, которая несёт смысл — axe промолчит, пользователь потеряет контекст- Контраст 4.5:1 на тексте, который лежит поверх видео — на отдельном кадре проходит, в движении нет
- Фокус виден, но это дефолтная синяя рамка на синем фоне бренда — технически есть, практически нет
Как объяснить это команде и бизнесу
Главная проблема не в инструментах, а в том, что доступность воспринимается как «дополнительная работа в конце». Дальше — несколько ходов, которые в реальных командах работают.
Переводим на язык продукта
- Не «WCAG 2.2 AA», а «35% наших пользователей хотя бы раз пользуются клавиатурой для навигации — мы их сейчас теряем на шаге Х»
- Не «контраст не проходит», а «этот текст не читается на солнце с телефона — мы проверили на улице»
- Не «нужна семантика», а «голосовой ассистент и поиск по странице не находят эту кнопку»
Встраиваем в DoD, а не в «отдельный спринт доступности»
- Компонент в дизайн-системе считается готовым, когда у него есть состояние focus, описаны клавиатурные шорткаты и контраст проверен во всех темах
- PR-шаблон содержит строку про доступность — не чекбокс «я проверил», а конкретно: «прошёл по Tab, проверил скринридером, axe зелёный»
- Баги доступности заводятся с тем же приоритетом, что функциональные — иначе они вечно «потом»
Вопросы для ревью фичи
- Если у пользователя нет мыши — он сможет завершить этот сценарий?
- Если выключить звук и цвет — какая информация теряется?
- Что услышит скринридер на этом экране в первые пять секунд?
- Где здесь самое узкое место — и почему мы решили его не чинить сейчас?
Итог сегмента
Инструменты не делают продукт доступным. Они показывают, где он точно сломан. Всё остальное — решение команды: какой контекст мы проверяем, кому объясняем, на каком этапе ловим. Автоматика — нижняя планка. Реальная доступность начинается с вопроса «а как этим пользоваться без того, на что мы по умолчанию рассчитывали».
Дальше — то, что превращает «инструменты показали красное/зелёное» в реальную привычку команды: короткие чеклисты, ловушки в самом процессе и вопросы, которые имеет смысл задавать до того, как фича уехала в прод.
Чеклист перед мерджем
Не «полный аудит доступности», а минимум, который реалистично пройти за 10–15 минут на любой фиче.
Перед PR
- Прошёл флоу одной только клавиатурой от начала до конца — Tab, Shift+