ARIA-атрибут role с несколькими значениями

  • ARIA
  • HTML

Недавно случайно узнала, что ARIA-атрибут role может содержать больше одного значения. И это очень неожиданно, по крайней мере для меня.

Этот пост написала из исследовательского интереса, так что в нём нет большого количества полезных практических советов. А что-то даже лучше не применять на практике.

Небольшая справка о роли элемента

Роль содержит информацию о функциях элемента и как с ним можно взаимодействовать. К примеру, о <button> скринридер объявит, что это кнопка, а также сможет на неё нажать.

У элементов может быть либо встроенная роль, либо явно заданная в атрибуте role.

Есть много категорий и видов ролей, и существуют чёткие правила их явного использования. Например, нельзя менять роли при взаимодействии с элементом или задавать абстрактные (landmark, section, widget и другие). Также есть роли, которые предполагают вложенные элементы. Например, в элемент с role="menu" должен быть вложен как минимум один с menuitem. Однако главное правило — стараться как можно реже явно задавать роли, особенно таким образом переопределять семантику элементов.

Что там в документации

В WAI-ARIA (Web Accessibility Initiative — Accessible Rich Internet Applications), как в самом очевидном источнике о role="", нет примеров с двумя ролями. И про несколько значений у этого атрибута пришлось поискать.

WAI-ARIA 1.1

В пункте 7.1 Role Attribute собраны характеристики атрибута роли, которые нужно учитывать в языках реализации (host languages):

  • Имя атрибута должно быть role.
  • Значение атрибута должно допускать список токенов в качестве значения.
  • Появление имени литерала любой конкретной роли в качестве одного из токенов не должно само по себе делать недопустимым значение атрибута в синтаксисе языка реализации.
  • Первый литерал имени неабстрактной роли в списке токенов в атрибуте role определяет роль в соответствии с тем, как User Agent должен обрабатывать элемент. То, как User Agent обрабатывает роли, установлено в Core Accessibility API Mappings.

Раз WAI-ARIA отсылает нас к другой документации, то давайте почитаем теперь её.

Core Accessibility API Mappings 1.1

Это спецификация для браузеров и любого другого User Agent. В ней описано, как они должны взаимодействовать с Accessibility API.

В пункте 5.4 Role mapping есть то, что нам нужно:

Традиционно Accessibility API платформы имеют ограниченный набор заранее установленных ролей, которые ожидаются вспомогательными технологиями на этой платформе, и предоставлены могут быть только одна или две роли. Напротив, WAI-ARIA позволяет указывать несколько ролей в виде упорядоченного набора валидных токенов ролей, разделённых пробелами. Дополнительные роли — фоллбэк для других ролей, что похоже на концепцию указания нескольких шрифтов на случай, если первый тип шрифта не поддерживается.

В этом пункте собраны и сами правила работы с ролями из WAI-ARIA.

  1. User Agent должен использовать первый токен в их последовательности в значении атрибута роли, который соответствует имени любой неабстрактной роли из таблицы маппинга ролей… Обратите внимание, что, когда роли из WAI-ARIA перезаписывают семантику языков реализации, то DOM (Document Object Model) не изменяется, только дерево доступности.
  2. User Agent не должен мапировать роли, которые определены в спецификации WAI-ARIA как «абстрактные», с помощью стандартного механизма ролей Accessibility API.

HTML

Давным-давно в спецификации по HTML был пункт 3.2.7.3.1 ARIA Role Attribute, который тоже описывал возможность добавлять несколько ролей для элемента:

Для каждого HTML-элемента можно указать ARIA-атрибут role. Это атрибут роли из ARIA, который определён в спецификации в Section 5.4 Definition of Roles.
Атрибут, если он задан, должен иметь значение, которое выглядит как набор токенов, разделённых пробелами и представляющих различные роли WAI-ARIA, к которым относится элемент.
Роль WAI-ARIA, которая назначена для HTML-элемента, первая неабстрактная роль, найденная в списке значений, сгенерированных, когда атрибут role разделён пробелами.

Пункта больше нет, но интернет помнит всё.

Будущее

В следующих, пока что черновых версиях WAI-ARIA 1.2 и Core Accessibility API Mappings 1.2, нет ничего нового про несколько атрибутов у role="". Единственное, в спецификации для User Agent появилось больше деталей о поддержке ролей разными реализациями Accessibility API.

Перевод с документационного

Какие выводы можно сделать после путешествия по спецификациям?

  • В атрибуте role можно указывать несколько значений.
  • Несколько значений перечисляется стандартно через пробел.
  • Несколько ролей нужны для фоллбэка. Если первая роль не поддерживается или не существует, то применяется вторая и так далее.
  • Если это абстрактная роль, то браузер и скринридер её проигнорируют.

Тестируем

Давайте проверим, что будут делать браузеры и скринридеры с двумя значениями в атрибуте role. Поэкспериментируем в Chrome 97, Firefox 96 и Safari 14 с NVDA 2021.2 и десктопным VoiceOver.

Кстати, в старых браузерах и скринридерах это не получится проверить. Они просто игнорируют role="" с несколькими значениями. Имейте это в виду.

Разметка, которую буду тестировать, может напугать. Это проверка работы одного атрибута, так что решила хотя бы раз в жизни использовать запрещённые приёмы 😀 В  реальных проектах так лучше никогда не делать. Это ужасный антипаттерн.

Оба значения существуют

<div role="button link" aria-label="Это не кнопка" tabindex="1">Что-то преступное</div>
  • NVDA и Chrome: «Это не кнопка, кнопка».
  • NVDA и Firefox: «Кнопка».
  • VoiceOver и Safari: «Это не кнопка».

В Chrome и Safari <div>role="button link" получил роль button, в Firefox — pushbutton.

Деревья доступности в инструментах разработчика в Chrome, Firefox и Safari. Во всех трёх браузерах aria-label содержит текст «Это не кнопка», вычисленная роль элемента — button и pushbutton.

Вывод: когда два значения валидные, то в дерево попадает самое первое.

Одно значение существует, другое нет

<div role="opossum button" aria-label="Это не кнопка" tabindex="1">Что-то преступное</div>
  • NVDA и Chrome: «Это не кнопка, кнопка».
  • NVDA и Firefox: «Кнопка».
  • VoiceOver и Safari: «Это не кнопка».

В Chrome и Safari <div>role="opossum button" получил роль button, в Firefox — pushbutton.

Деревья доступности в инструментах разработчика в Chrome, Firefox и Safari. И снова во всех трёх браузерах aria-label содержит текст «Это не кнопка», вычисленная роль элемента — button и pushbutton.

Вывод: если одно значение невалидное, а второе валидное, то в дерево попадает существующее.

Одно значение абстрактное, другое нет

<div role="widget button" aria-label="Это не кнопка" tabindex="1">Что-то преступное</div>
  • NVDA и Chrome: «Это не кнопка, кнопка».
  • NVDA и Firefox: «Кнопка».
  • VoiceOver и Safari: «Это не кнопка».

В Chrome и Safari <div>role="widget button" получил неабстрактную роль button, в Firefox — pushbutton.

Деревья доступности в инструментах разработчика в Chrome, Firefox и Safari. Во всех трёх браузерах aria-label содержит текст «Это не кнопка», вычисленная роль — button и pushbutton.

Вывод: когда есть абстрактная роль, то она игнорируется и применяется неабстрактная.

Обоих значений не существует

<div role="tapir opossum" aria-label="Это не кнопка" tabindex="1">Что-то преступное</div>
  • NVDA и Chrome: ничего не объявляет.
  • NVDA и Firefox: ничего не объявляет.
  • VoiceOver и Safari: «Это не кнопка». Объявляет только содержимое атрибута aria-label.

В Chrome для <div>role="tapir opossum" вычислена роль generic, в Firefox — text leaf, а в Safari просто не нашлось подходящей роли.

generic — это встроенная роль <div>. Это значит, что перед нами безымянный элемент-контейнер без семантического значения. А text leaf означает какой-то текстовый контент.

Деревья доступности в инструментах разработчика в Chrome, Firefox и Safari. Во всех трёх браузерах aria-label содержит текст «Это не кнопка», вычисленная роль — generic, text leaf, а в одном случае «Нет подходящих ролей ARIA».

Вывод: если оба значения невалидные, то в дерево доступности или попадает встроенная роль элемента, или ничего не вычисляется. Зависит от браузера.

Финальные мысли

Всё это время WAI-ARIA предусматривала возможность задавать для атрибута role больше одного значения, но не особо это афишировала.

Не думаю, что это ужасное упущение в спецификации. Сложно представить, для каких ролей нужны фоллбеки в современных браузерах. К тому же, с атрибутом role и так легко запутаться. Когда у тебя есть возможность задать бесконечное количество ролей, то это ещё больше усложняет разметку и может привести к неожиданным ошибкам.

Что почитать


Спасибо Василию Дудину за помощь с редактированием.

Другие посты