Семантика и ARIA

Что это такое

Всё, что встречает ассистивная технология, она описывает тремя вещами: ролью элемента, его доступным именем и состоянием. Откуда браузер берёт эти значения — вопрос семантики: у button роль «button», и он получает фокус; имя input даёт связанный с ним label; чекбокс сообщает, отмечен он или нет. А ARIA — набор атрибутов, которые переопределяют или дополняют сказанное разметкой; он нужен там, где ни один нативный элемент не подходит.

Почему это важно

Элемент управления без имени объявляется как «button», и пользователь не понимает, что перед ним. Состояние, переданное только цветом — красная рамка, серая строка, — для того, кто слушает, а не смотрит, не существует. И это не редкие случаи: так описан интерфейс для другого чувства. Зато сама правка по большей части не требует ничего, кроме сдержанности: правильная ARIA — обычно никакой ARIA, ведь нативный элемент уже несёт нужную роль, имя и поведение с клавиатуры, а написанному вручную заменителю приходится воспроизводить все три правильно.

Ключевые идеи

Сначала нативный элемент

<button>, <a href>, <input type="checkbox">, <select> и <details> приходят с уже реализованными ролями, поведением с клавиатуры, обработкой фокуса и участием в форме. Воспроизвести что-либо из этого через div и ARIA возможно и почти всегда хуже: атрибуты ARIA описывают элемент управления, но не заставляют его работать.

<!-- объявляется как «Подписаться, button» и работает с клавиатуры -->
<button type="button">Подписаться</button>

Каждому элементу управления нужно доступное имя

Имя берётся из содержимого элемента, связанного label или, когда ни то ни другое невозможно, из aria-label / aria-labelledby. Иконки — частая ошибка: у кнопки, единственный потомок которой — иконка SVG, нет текста, поэтому иконку нужно скрыть от дерева, а кнопке дать имя.

<button type="button" aria-label="Закрыть диалог">
  <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">…</svg>
</button>

ARIA — для пробелов, а не для украшения

aria-hidden="true" убирает элемент из дерева доступности — полезно для декоративной иконки, разрушительно для фокусируемого элемента управления. role заменяет роль элемента, и к нему стоит прибегать только для виджетов, у которых действительно нет HTML-эквивалента, например списка вкладок или live-региона.

Объявляйте изменения, которые происходят без перехода

Регион, который обновляется без загрузки страницы — фильтр поиска, подтверждение сохранения, — зрячий пользователь увидит, а все остальные нет. Чтобы новое содержимое было объявлено, пока пользователь не занят, на регионе ставят aria-live="polite"; пользуйтесь этим умеренно и делайте объявления короткими.

<p role="status" aria-live="polite">{message}</p>

Не передавайте смысл только цветом

Обязательные поля, ошибки, выбранные строки и статусы нужны со второй подсказкой: текстом, иконкой, подчёркиванием, узором рамки. Это же исправление работает и для людей с дальтонизмом, и для всех, кто читает с выцветшего экрана при дневном свете.

Практика

Дайте имя каждому элементу управления на странице

Откройте страницу, которую сопровождаете, перечислите все интерактивные элементы и выпишите доступное имя, которое скринридер объявил бы для каждого. Сверьте ответы с деревом доступности в браузере.

Готово, когда: ни один элемент управления не объявляется без имени, и у каждой кнопки-иконки есть либо видимая подпись, либо aria-label, называющий действие.

Замените кликабельный div на нужный элемент

Найдите div с обработчиком onClick, решите, ведёт он куда-то или совершает действие, и используйте a или button, сохранив оформление.

Готово, когда: элемент достигается клавишей Tab, активируется Enter и Space там, где это уместно, а дерево доступности сообщает соответствующую роль.

Частые ошибки

  • aria-hidden="true" на фокусируемом элементе — он остаётся в порядке табуляции, но у него нет имени, и пользователь с клавиатуры попадает в тишину; исправить: скрывайте только декоративное содержимое, а элементу управления дайте собственное имя.
  • Кнопка, собранная из div с role="button" — Enter и Space её не активируют, и форма никогда не отправляется; исправить: используйте настоящий button и оформите его.
  • Placeholder как единственная подпись — имя исчезает при вводе и объявляется ненадёжно; исправить: добавьте label, связанный через for и id.
  • Молчание при изменении содержимого — фильтр, который обновляется без объявления, выглядит для пользователя скринридера сломанным; исправить: пометьте регион aria-live="polite" и держите сообщение коротким.
  • Ошибка, переданная только красной рамкой — ошибка невидима для всех, кто не различает цвет; исправить: добавьте текстовое сообщение, связанное с полем, и иконку или префикс как вторую подсказку.

Что читать дальше

  • Язык гипертекстовой разметки (HTML) (02-frontend/03-html) — семантика, на которой строится этот урок; выбранный элемент задаёт роль, которую слышит пользователь.
  • Клавиатурный доступ и фокус (02-frontend/11-accessibility-wcag-a11y/02-keyboard-and-focus) — вторая половина той же гарантии.
  • Figma (программа для дизайна) (03-design-ux/12-figma) — место, где решения о цвете и контрасте часто принимаются задолго до появления разметки.