Доступность сайтов: WCAG, скринридеры, клавиатурная навигация
На сайте крупного банка была кнопка «Подать заявку». Визуально она выглядела как кнопка. В разметке это был <div class="btn" onclick="...">. Скринридер NVDA её не анонсировал как интерактивный элемент, Tab её пропускал, Enter не срабатывал. Для 285 000 незрячих пользователей в России этот банк просто не существовал как онлайн-сервис.
Семантическая разметка: основа всего
Большинство проблем доступности решается правильным HTML, а не дополнительными ARIA-атрибутами. <button> вместо <div onclick>, <nav> вместо <div class="navigation">, <h1>–<h6> в правильной иерархии, <label for="field-id"> вместо <div class="label">.
ARIA нужна там, где нативный HTML не справляется: кастомные компоненты — выпадающие меню, тултипы, модальные окна, табы, accordion. И вот тут начинается сложность.
Типичная ошибка в кастомных дропдаунах: открывается список вариантов, скринридер не знает, что это combobox, не объявляет количество опций, не говорит какая выбрана, фокус не переходит в список при открытии. Правильная реализация:
-
role="combobox"на инпуте -
aria-expanded="true/false"при открытии/закрытии -
aria-controls="listbox-id"указывает на список -
aria-activedescendant— ID текущего выбранного элемента -
role="option"иaria-selectedна каждом варианте
Это не теория, это то, что тестируется скринридером. NVDA + Chrome или VoiceOver + Safari — обязательная часть QA.
Клавиатурная навигация
Tab-порядок должен совпадать с визуальным порядком элементов. Если в HTML кнопка «Отмена» стоит перед «Подтвердить», но CSS их меняет местами — пользователь клавиатуры в замешательстве.
Focus trap в модальных окнах. Когда модалка открывается, Tab должен циклиться только внутри неё, не уходить за её пределы. При закрытии — возврат фокуса на элемент, который открыл модалку. Без этого пользователь клавиатуры после закрытия оказывается в начале страницы.
tabindex="-1" — элемент не попадает в Tab-последовательность, но может получить фокус программно. Используется для элементов, которые получают фокус через JavaScript (заголовки секций, на которые прокручиваемся после навигации по якорям).
tabindex="1" и выше — почти всегда ошибка. Явный порядок tabindex ломает естественный порядок и создаёт непредсказуемое поведение. Управляйте порядком через DOM-порядок, не через tabindex.
Skip links — ссылка «Перейти к содержимому», скрытая визуально, но видимая при Tab. Позволяет пользователям скринридеров пропустить повторяющуюся навигацию. position: absolute; left: -9999px при обычном состоянии, position: static при :focus.
Цвет и контраст
WCAG 2.1 AA требует контраст 4.5:1 для обычного текста, 3:1 для крупного (18px+ или 14px+ bold). AAA требует 7:1 и 4.5:1.
Самые частые нарушения: серый placeholder в инпутах (#999 на белом = 2.9:1), светло-серый secondary текст, белый текст на пастельном фоне.
Цвет не должен быть единственным индикатором: «поля обязательные поля выделены красным» без звёздочки или текстового указания — нарушение для людей с цветовой слепотой.
Инструменты проверки: axe DevTools, WAVE, встроенный Accessibility Inspector в Chrome DevTools. axe-core интегрируется в Playwright-тесты: автоматическая проверка страниц на 80+ правил WCAG при каждом деплое.
Медиаконтент и динамика
Изображения без alt — частый базовый провал. Но alt должен быть смысловым: не alt="image_123.jpg", не alt="изображение", а описание содержимого релевантное контексту. Декоративные изображения — alt="" (пустой, не отсутствующий атрибут).
Видео должно иметь субтитры. YouTube автосубтитры — не стандарт, они ошибаются. WebVTT-файлы с корректными субтитрами для всего образовательного и маркетингового видеоконтента.
Анимации — проблема для пользователей с вестибулярными расстройствами. @media (prefers-reduced-motion: reduce) — медиа-запрос, отключающий или замедляющий анимации для пользователей с такой настройкой в ОС. Параллакс-эффекты, бесконечные анимации, scroll-based transitions должны уважать это предпочтение.
WCAG 2.2 и что изменилось
WCAG 2.2 стал официальным в октябре 2023. Новые критерии включают:
- 2.5.7 Dragging Movements (AA): все drag-операции должны иметь клавиатурную альтернативу
- 2.5.8 Target Size (AA): минимальный размер интерактивного элемента 24x24px (не только touch)
- 3.2.6 Consistent Help (A): если есть контакт/чат поддержки, его расположение должно быть консистентным на всех страницах
- 3.3.7 Redundant Entry (A): не заставлять вводить одну информацию дважды в одной сессии
Аудит и устранение нарушений
Автоматические инструменты находят около 30–40% нарушений WCAG. Остальное — только ручное тестирование. Минимальный сценарий ручного тестирования: пройти весь критический user flow (регистрация, покупка, форма заявки) только клавиатурой и со скринридером.
Процесс работы
Аудит начинается с автоматического сканирования (axe, Lighthouse), затем ручное тестирование ключевых сценариев. Формируем приоритизированный список нарушений: P1 (блокируют использование), P2 (создают сложности), P3 (улучшения). Исправление идёт итерациями, встраиваем проверки в CI чтобы не накапливать регрессию.
Сроки
Аудит сайта с отчётом: 3–7 дней. Устранение нарушений уровня A/AA на существующем проекте: 3–8 недель в зависимости от объёма и технического долга. Разработка нового проекта с соблюдением WCAG 2.2 AA: добавляет 15–25% к срокам разработки.







