Ответ на вопрос
Кратко и по делу — что нужно делать и проверять, чтобы интерфейс был доступен с клавиатуры и экранных читалок.
1) Основной принцип
- Всегда предпочитать семантический HTML перед ARIA: используйте ``, ``, ``, заголовки ``–``, списки `/`, ``, ``, ``, ``.
- ARIA только когда семантика отсутствует или недостаточна (см. WAI-ARIA Authoring Practices).
2) Ландмарки и структура
- Используйте семантические элементы или роли: `` (role="main"), `` (role="navigation"), `` (role="banner"), `` (role="complementary"), `` (role="contentinfo").
- Чёткая и иерархичная структура заголовков (``...``) для навигации чтением.
3) Клавиатурная навигация и фокус
- Фокусируемые элементы — только интерактивные: ``, ``, ``. Не делайте дивы интерактивными без необходимости.
- Для нелинейных элементов используйте `tabindex="0"` (включить в таб-цикл) и `tabindex="-1"` (для программной фокусировки).
- Видимость фокуса: обеспечьте стили для `:focus` и `:focus-visible`.
- Поддерживайте стандартные клавиши: Enter/Space для активации кнопок, стрелки для меню/радио/табов (следовать ARIA APG), Esc для закрытия диалогов/меню.
- Для составных виджетов используйте паттерн roving tabindex: ровно один элемент имеет `tabindex="0"`, остальные `-1`, переключайте при стрелках.
4) Модальные окна и управление фокусом
- Фокус при открытии ставьте на первый фокусируемый элемент или на контейнер с `tabindex="-1"`; при закрытии возвращайте фокус к элементу, открывшему модал.
- Трап фокуса внутри модала (циклически избегать ухода фокуса за пределы).
- Установите `aria-modal="true"` и роль `role="dialog"` (и `aria-labelledby`/`aria-describedby`).
5) Метки и формы
- Каждое поле имеет `` или `aria-label`/`aria-labelledby`. Предпочитайте ``.
- Ошибки сообщайте явно: `aria-invalid="true"`, связывайте сообщение через `aria-describedby`.
- Для обязательных полей явно указывать статус и пояснять ошибки, а экранным читалкам — доступно объявлять.
6) ARIA-атрибуты и состояния (часто используемые)
- `aria-label`, `aria-labelledby`, `aria-describedby`.
- `aria-hidden="true"` — скрывает от AT; не применять для интерактивных видимых элементов.
- `aria-expanded`, `aria-controls` — раскрывающиеся панели/меню.
- `role="button"` только если элемент не может быть заменён на ``.
- `aria-pressed` для toggle-кнопок, `aria-checked` для переключателей.
- `aria-live="polite"` / `aria-live="assertive"` и `role="status"`/`role="alert"` для динамических сообщений.
7) Динамическое содержимое
- Обновления важной информации — использовать `aria-live` или `role="status"`; для критичных ошибок — `role="alert"`.
- При изменении видимости содержимого корректно обновляйте `aria-hidden`.
- Обновления DOM должны сопровождаться перемещением фокуса или ясным оповещением через `aria-live`.
8) Кастомные контролы
- Следуйте WAI-ARIA Authoring Practices: реализуйте ожидаемую клавиатурную модель (Enter/Space, стрелки, Home/End).
- Объявляйте роль (например, `role="menu"`, `role="tablist"/role="tab"`, `role="listbox"`), состояния (`aria-selected`, `aria-activedescendant`).
- Реализуйте roving tabindex или `aria-activedescendant` для упрощения навигации.
9) Сквозная навигация (skip links) и порядок табуляции
- Добавьте "Skip to content" ссылку (``) видимую при фокусе.
- Порядок DOM должен соответствовать визуальному порядку; избегайте изменения визуального порядка без сохранения логического порядка.
10) Тесты (ручные и автоматизированные)
- Ручное тестирование клавиатурой:
- Полностью управлять интерфейсом клавиатурой (Tab, Shift+Tab, Enter, Space, стрелки, Esc, Home/End).
- Проверить фокус-видимость, порядок, нет ли "фокус-провалов" (фокус вне видимой области).
- Открыть/закрыть модалы, меню; проверять trap/restore фокуса.
- Ручное тестирование с экранными читалками:
- VoiceOver (macOS + Safari), NVDA (Windows + Firefox/Chrome), JAWS (Windows), TalkBack (Android).
- Проверять: правильность чтения меток, состояний (`expanded`, `selected`, `checked`), порядок чтения, объявления динамических обновлений.
- Автоматизированные инструменты:
- axe-core, Lighthouse, Pa11y, WAVE, eslint-plugin-jsx-a11y.
- Интеграционные/unit тесты: jest-axe, axe-webdriverjs.
- DevTools:
- Используйте Accessibility pane в Chrome/Firefox для проверки роли, имени и свойства, contrast, focusable.
- Тестовые сценарии:
- Навигация по главной странице, формам, меню, модальным окнам, вкладкам, интерактивным таблицам. Проверить ошибки формы, сообщения успеха, динамические загрузки.
11) Контроль качества и документация
- Поддерживайте чеклист доступности (ARIA, семантика, клавиатура, читалки) в проекте.
- Покрывайте критичные флоу тестами (ручными и автоматизированными).
- Логируйте известные проблемы и обходы для будущих релизов.
12) Полезные практики и примеры (кратко)
- Для кнопки: используйте `` вместо `div role="button"`.
- Для раскрывающегося списка: `button aria-expanded="false" aria-controls="menu"`, а меню — `id="menu" role="menu"`.
- Для табов: `role="tablist"` → `role="tab"` с `aria-selected`, панели — `role="tabpanel"` и `aria-labelledby`.
Контрольный список для быстрой проверки:
- Семантический HTML использован?
- Все интерактивные элементы доступны через Tab и управляемы клавиатурой?
- Видимость фокуса присутствует и логична?
- Метки полей/кнопок корректны и доступны читалкам?
- Динамические обновления объявляются (`aria-live`/role)?
- Модальные окна фокус-трапят и восстанавливают фокус?
- Использованы правильные ARIA-роли/состояния (не избыточно)?
- Протестировано с NVDA/VoiceOver/TalkBack и автоматическими сканерами?
Этого набора достаточно для грамотной реализации и проверки доступности интерфейса для клавиатуры и экранных читалок.
Еще