Перевод статьи: Ben Myers — What Is ARIA?
Не секрет, что сегодняшние сайты становятся все более сложными. Веб-страницы теперь больше напоминают динамические, живые приложения. Разработчики комбинируют и оформляют элементы HTML для создания новых пользовательских интерфейсов. Однако пользователям с ограниченными возможностями может быть непросто разобраться в этом новом мире.
Одним из инструментов, разработанных для решения этой проблемы, является ARIA. Сокращенно от Accessible Rich Internet Applications (Доступные многофункциональные интернет-приложений), ARIA — это подмножество атрибутов HTML (обычно с префиксом aria-), которые изменяют то, как вспомогательные программы, такие как программы чтения с экрана, распознают ваши страницы.
К сожалению, разработчики часто неправильно понимают ARIA и применяют ее неправильно, что ведет к ухудшению работы пользователей с ограниченными возможностями. В 2017 году ресурс веб-доступности WebAIM сообщил:
Когда WebAIM оценивает веб-сайты клиентов на предмет доступности, мы часто тратим больше времени на оценку и составление отчетов об использовании ARIA, чем на любую другую проблему. Почти каждый отчет, который мы создаем, содержит раздел, предупреждающий о злоупотреблении ARIA и описывающий использование ARIA, которые необходимо исправить или, чаще всего, удалить.
Jon Whiting, To ARIA! The Cause of, and Solution to, All Our Accessibility Problems
Самый сильный индикатор того, что страница будет иметь множество ошибок доступности, — это наличие ARIA. Страницы с ARIA имеют на 65% больше проблем, чем без него. И это становится все хуже. Это ОЧЕНЬ тревожно!
Отчет WebAIM показывает нам, что более сложные страницы и использование библиотек и структур могут привести как к большему количеству ситуаций, требующих ARIA, так и к большему количеству ошибок. Таким образом, кажется, что у разработчиков нет понимания того, что такое ARIA и как ее следует использовать.
Это может быть связано с тем, что существует множество атрибутов ARIA, каждый из которых имеет свои (правда, иногда нишевые) варианты использования. Это так же делать ARIA сложным для понимания.
Кроме того, ARIA не всегда полноценно описывается в документацию по веб-разработке. Кажется что его часто используют для того чтобы сделать элемент «более доступным». Мой друг признался, что скопировал ARIA из примера кода, потому что пример из документации включал его. Но не понимая что именно делает ARIA, разработчики вполне разумно могут предположить, что больше ARIA означает лучшую доступность.
В этой статье я хочу рассказать что такое ARIA, что она делает, почему вы должны ее использовать ее, и когда ее не нужно использовать.
В моем последнем посте я представил дерево доступности: альтернативный DOM, который браузеры создают специально для вспомогательных программ. Эти деревья доступности описывают страницу в терминах доступных объектов: структуры данных, предоставляемые операционной системой, которые представляют различные виды элементов пользовательского интерфейса и элементы управления, такие как текстовые узлы, checkbox или кнопки.
Доступные объекты описывают элементы пользовательского интерфейса как наборы свойств. Например, свойства, которые могут описывать checkbox, включают:
Мы можем разбить эти атрибуты на четыре типа:
Эти качества охватывают все, что пользователь может захотеть узнать о функции элемента, в то же время пропуская все что связано с внешним видом элемента.
Семантическая разметка эта такая разметка в которой максимально используются элементы HTML, которые лучше всего отражают желаемое поведение. Например, если вы хотите, чтобы элемент, при нажатии отправлял бы форму или выполнял какое-либо действие на странице, обычно лучше использовать тег <button>
. Когда мы пишем семантический HTML, браузеру гораздо проще выбирать нужные объекты. Кроме того, браузер может сделать грязную работу, чтобы убедиться, что объекты имеют все необходимые свойства, без каких-либо дополнительных усилий с нашей стороны.
Тем не менее, возможности семантики не без граничны. Иногда нам нужны новые, более сложные операции, которые семантические элементы просто еще не поддерживают, такие как:
Что делать в этих случаях? По-прежнему важно спроектировать весь функционал так, чтобы вспомогательные программы могли все это понять. Во-первых, мы должны реализовать как можно больше с помощью семантической разметки. Затем мы используем атрибуты ARIA, чтобы настроить/подкорректировать дерево доступности.
ARIA не изменяет DOM и не добавляет новую функциональность к элементам. Она никак не изменит поведение элементов. ARIA исключительно управляет представлением элементов в дереве доступности. Другими словами, ARIA используется для изменения роли, имени, состояния и свойств элемента для вспомогательных технологий.
Это прекрасно в теории, но как это работает на практике?
Давай те рассмотрим как работает Aria на примере переключателя (switch):
<div id="container"> <span tabindex="0" class="toggle-switch" > <span class="toggle-knob"></span> </span> <div> Dark mode is <span class="status">off</span> </div> </div>
.toggle-switch, .toggle-switch .toggle-knob { transition: all 0.2s ease-in; } .toggle-switch { height: 90px; width: 165px; display: inline-block; background-color: #333333; margin: 6px; margin-bottom: 15px; border-radius: 90px; cursor: pointer; text-align: left; } .toggle-switch .toggle-knob { width: 84px; height: 78px; display: inline-block; background-color: #ffffff; border-radius: 78px; margin: 6px 9px; } .toggle-switch.active { background-color: #f31455; } .toggle-switch.active .toggle-knob { margin-left: 72px; } /* Focus styles */.toggle-switch:focus { outline: none; } .toggle-switch:focus .toggle-knob { box-shadow: 0px 0px 5px 5px #229abf; }
const toggler = document.querySelector('.toggle-switch'); const switchStatus = document.querySelector('.status'); let switchIsActive = false; // Вызывается всякий раз, когда вы нажимаете на переключатель function handleClick() { // Заставляет страницу переключаться между светлым и темным режимом document.body.classList.toggle('dark-mode'); // Вызывает тумблер, чтобы изменить внешний вид toggler.classList.toggle('active'); // Изменяет содержание статуса switchIsActive = !switchIsActive; switchStatus.innerHTML = switchIsActive ? 'on' : 'off'; } // Добавляет события клавиатуры в переключатель toggler.addEventListener('keydown', function (event) { if (event.key === ' ') { // Prevents unintentional form submissions, page scrolls, the like event.preventDefault(); handleClick(); } }); toggler.onclick = handleClick;
Если вы нажмете на переключатель, вы активируете темный режим. Нажмите на него еще раз, и вы вернетесь в светлый режим. Переключение должно работать даже с клавиатуры — вы можете перейти к нему и вызвать его, нажав пробел.
Но у этого переключателя есть небольшая проблема. Если вы перейдете к нему с помощью программы чтения с экрана, вы услышите что-то вроде этого:
VoiceOver, просто прочитает «group»
Пользователи программы чтения с экрана не будут знать, что это за элемент, для чего он нужен, и даже то, что он кликабелен. Пользователи других вспомогательных технологий будут также разочарованы. Это то, что в бизнесе называется «проблемой». К счастью, мы можем попытаться исправить это с помощью ARIA. Мы рассмотрим, как ARIA изменяет имена, роли, состояния и свойства, добавляя атрибуты ARIA к этому переключателю.
Если вы хотите использовать код локально, чтобы следовать по нему, вы можете клонировать его из GitHub. Если у вас нет программы для чтения с экрана, выполните следующие действия, чтобы просмотреть дерево доступности вашего браузера.
Прежде всего, как мы можем убедиться, что вспомогательные технологии могут понять, что наш элемент — это переключатель, а не проста группа элементов?
Браузер на самом деле не знает, что делать с нашим переключателем или как лучше всего использовать его для вспомогательных программ. Поскольку наш переключатель — это просто <span> с другим <span> внутри него, лучшим предположением браузера является то, что это общая группа элементов. К сожалению, это не помогает пользователям вспомогательных программ понять, что это за элемент или как им следует взаимодействовать с ним.
Мы можем помочь браузеру, предоставив нашему переключателю атрибут role. role может принимать множество возможных значений, таких как button, link, slider или table. Некоторые из этих значений имеют соответствующие семантические элементы HTML, но некоторые нет.
Мы хотим выбрать роль, которая лучше всего описывает наш элемент как переключатель. В нашем случае есть две роли, которые описывают элементы, которые чередуются между двумя противоположными состояниями: checkbox и switch. Эти роли функционально очень похожи, за исключением того, что состояния checkbox checked и unchecked, а switch использует on и off. Роль switch также имеет более слабую поддержку, чем checkbox. Мы будем использовать switch, но вы можете использовать checkbox самостоятельно.
<div id="container"> <span tabindex="0" class="toggle-switch" role="switch" > <span class="toggle-knob"></span> </span> <div> Dark mode is <span class="status">off</span> </div> </div>
Теперь, когда мы перейдем к нашему переключателю с помощью программы чтения с экрана, мы получим более точное описание этого элемента:
VoiceOver прочитает «off, switch»
Когда я немного задержался на этом элементе с активным VoiceOver, VoiceOver сказал мне, как я могу взаимодействовать с элементом с помощью клавиши пробела:
Вспомогательные технологии теперь могут использовать эти роли для предоставления дополнительных функций, облегчающих навигацию по странице для пользователей с ограниченными возможностями. Например, когда пользователь вводит голосовую команду «click button», программа распознавания речи Dragon NaturallySpeaking подсвечивает все кнопки на странице. Программы чтения с экрана часто предоставляют ярлыки для навигации между различными элементами одной и той же роли — JAWS предоставляет горячие клавиши, а VoiceOver предоставляет Rotor для этой цели.
Важно отметить, что роль — это обещание. Вы обещаете пользователям, что они могут взаимодействовать с элементами определенным образом и будут вести себя предсказуемо. Например, пользователи ожидают от переключателей switches следующее:
Указание role для элемента не приведет к автоматическому добавлению каких-либо ожидаемых функций. Это не сделает наш элемент фокусируемым или добавит ключевые события. Разработчик должен выполнить это обещание. В случае с нашим переключателем я уже обработал это с помощью tabindex и добавил прослушиватель событий keydown.
Хорошо, что пользователи и вспомогательные технологии знают, что наш элемент — это switch. Теперь, однако, они могли бы спросить себя для чего этот переключатель?
Доступное имя элемента — это его метка или идентификатор. Программы чтения с экрана объявляют имя элемента, когда пользователь переходит к этому элементу. Пользователи программ распознавания речи могут также использовать имя элемента для нацеливания на этот элемент в голосовой команде. Имена изображений происходят из их alt текста , а поля формы получают свои имена из связанных с ними <label> элементов . Большинство элементов получают свои имена из своего текстового содержимого.
Иногда доступное имя по умолчанию недостаточно. В некоторых случаях, оправданна ручная установка доступного имени. Например когда:
ARIA предлагает два атрибута для изменения имени элемента: aria-label и aria-labelledby.
Когда вы указываете aria-label для элемента, вы переопределяете любое имя, которое имело этот элемент, и заменяете его содержимым этого атрибута aria-label. Возьмите кнопку со значком увеличительного стекла. Мы могли бы использовать aria-label, чтобы программы чтения с экрана перезаписывали содержимое кнопки и объявляли ее как «Search»:
<button aria-label="Search"> <svg viewBox="0 0 22 22"> <!-- Some magnifying glass SVG icon --> </svg> </button>
Давайте добавим aria-label к нашему переключателю:
<div id="container"> <span tabindex="0" class="toggle-switch" role="switch" aria-label="Use dark mode" > <span class="toggle-knob"></span> </span> <div> Dark mode is <span class="status">off</span> </div> </div>
Если вы перейдете к переключателю с помощью программы чтения с экрана, вы услышите что-то вроде этого:
VoiceOver прочитает переключатель как «Use dark mode, off, switch«
aria-label лучше всего использовать, когда на странице еще нет видимой текстовой метки. В качестве альтернативы, если у нас уже есть ярлык на странице, мы могли бы использовать aria-labelledby. aria-labelledby берет идентификатор текстовой метки и использует содержимое этой метки в качестве доступного имени.
Например, мы могли бы использовать aria-labelledby, чтобы использовать заголовок в качестве метки для раздела оглавления.
<section> использует идентификатор id, чтобы указать, какой элемент должен служить его меткой. В результате весь раздел оглавления называется Table of Contents (Оглавление).
<section aria-labelledby="toc-heading"> <h1 id="toc-heading"> Table of Contents </h1> <ol> <!-- List items here --> </ol> </section>
Этот подход очень похож на использование элемента для атрибута, за исключением того, что он работает для всех элементов, а не только для полей формы.
Вот как будет выглядеть наш пример переключателя, если мы используем aria-labelledby вместо aria-label:
<div id="container"> <div id="toggle-label">Use Dark Mode</div> <span tabindex="0" class="toggle-switch" aria-labelledby="toggle-label" > <span class="toggle-knob"></span> </span> <div> Dark mode is <span class="status">off</span> </div> </div>
Примечание: во время написания этой статьи я узнал, что программы чтения с экрана могут игнорировать aria-label и aria-labelledby для статических элементов. Если ваши ярлыки не работают, убедитесь, что у вашего элемента есть landmark role или роль, которая подразумевает интерактивность.
Когда я перехожу к нашему переключателю с помощью программы чтения с экрана, она говорит мне, что он находится в выключенном состоянии. Тем не менее, когда я запускаю тумблер … он все равно говорит, что он выключен. Нам нужен способ, чтобы вспомогательные программы знали, когда состояние переключателя изменилось.
Атрибуты состояния ARIA описывают свойства элемента, которые могут изменяться способами, которые актуальны для пользователя. Они динамичны. Например, складные разделы (collapsible sections) позволяют пользователям нажимать кнопку, чтобы развернуть или свернуть содержимое. Когда пользователь программы чтения с экрана фокусируется на этой кнопке, вероятно, было бы полезно, если бы они знали, было ли содержимое в настоящее время развернуто или свернуто. Мы могли бы установить aria-extended=»false» на кнопку, а затем динамически изменять значение при каждом нажатии кнопки.
Еще один заслуживающий упоминания атрибут ARIA — aria-hidden. Всякий раз, когда элемент имеет aria-hidden=»true», он и любой его дочерний элемент немедленно удаляются из дерева доступности. Вспомогательные программы, использующие дерево, не будут знать, что этот элемент существует. Это полезно для презентационных элементов, которые украшают страницу, но создают беспорядочные возможности чтения с экрана. aria-hidden также может быть динамически переключен, например, чтобы скрыть содержимое страницы от программ чтения с экрана, когда открыто модальное окно.
Возвращаясь к нашему переключателю, элементы, для которых заданы role=»checkbox» или role=»switch», ожидают, что элемент будет иметь атрибут состояния, aria-checked, и будет меняться между «true» и «false» всякий раз, когда переключение срабатывает.
Следующий пример демонстрирует, как мы можем использовать JavaScript для изменения aria-checked:
<div id="container"> <span tabindex="0" class="toggle-switch" role="switch" aria-label="Use dark mode" aria-checked="false" > <span class="toggle-knob"></span> </span> <div> Dark mode is <span class="status">off</span> </div> </div>
const toggler = document.querySelector('.toggle-switch'); const switchStatus = document.querySelector('.status'); let switchIsActive = false; // Вызывается всякий раз, когда вы нажимаете на переключатель function handleClick() { // Заставляет страницу переключаться между светлым и темным режимом document.body.classList.toggle('dark-mode'); // Вызывает тумблер, чтобы изменить внешний вид toggler.classList.toggle('active'); // Изменяет содержание статуса switchIsActive = !switchIsActive; switchStatus.innerHTML = switchIsActive ? 'on' : 'off'; // Переключает aria-checked toggler.setAttribute('aria-checked', switchIsActive); } // Добавляет события клавиатуры в переключатель toggler.addEventListener('keydown', function (event) { if (event.key === ' ') { // Предотвращает непреднамеренное изменение формы, event.preventDefault(); handleClick(); } }); toggler.onclick = handleClick;
Попробуйте перейти к переключателю с помощью программы чтения с экрана. Нажмите на переключатель, чтобы включить темный режим. Теперь переключатель фактически объявляет, когда он включен:
VoiceOver прочитает текст «on, Use dark mode, switch»
Свойства ARIA — это атрибуты, которые описывают дополнительный контекст об элементе, который было бы полезно знать пользователю, и который не подвержен изменениям, таким как состояние. Примеры свойств:
Некоторые свойства ARIA устанавливают отношения между элементами. Например, вы можете использовать aria-describedby, чтобы связать элемент с другим элементом, который предоставляет более длинное описание:
<form> <label for="pass"> Enter a password: </label> <input id="pass" type="password" aria-describedby="pass-requirements" /> <p id="pass-requirements"> Your password must be at least 8 characters long. </p> </form>
В этом примере программа чтения экрана прочитает «Your password must be at least 8 characters long» как часть <input> объявления .
Спецификации ARIA Консорциума World Wide Web предоставляют пять правил использования ARIA. Первое правило можно прочитать как «не используйте ARIA», как это сделали некоторые, но это не совсем так. Правило звучит так:
Если вы можете использовать встроенный HTML-элемент с семантикой и поведением, которые вам требуются, вместо использования ARIA элементов (роли, состояния или свойства), чтобы сделать его доступным, то сделайте это.
Другими словами, ARIA должна быть инструментом в вашем арсенале, но она не должна быть первым инструментом, к которому вы обращаетесь. Вместо этого используйте семантику элементов, где это возможно. В нашем примере с переключателем это может выглядеть следующим образом (мы можем использовать встроенный checkbox и вообще не использовать ARIA):
<div id="container"> <label class="toggle-switch-semantic"> <span class="visually-hidden"> Use dark mode </span> <input type="checkbox" class="visually-hidden" /> <span class="toggle-switch"> <span class="toggle-knob"></span> </span> </label> <div> Dark mode is <span class="status">off</span> </div> </div>
.visually-hidden { border: 0; clip: rect(1px, 1px, 1px, 1px); clip-path: inset(50%); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; word-wrap: normal; } .toggle-switch, .toggle-switch .toggle-knob { transition: all 0.2s ease-in; } .toggle-switch { height: 90px; width: 165px; display: inline-block; background-color: #333333; margin: 6px; margin-bottom: 15px; border-radius: 90px; cursor: pointer; text-align: left; } .toggle-switch .toggle-knob { width: 84px; height: 78px; display: inline-block; background-color: #ffffff; border-radius: 78px; margin: 6px 9px; } .toggle-switch.active { background-color: #f31455; } .toggle-switch.active .toggle-knob { margin-left: 72px; } /* Focus styles */.toggle-switch-semantic input:focus + .toggle-switch .toggle-knob { box-shadow: 0px 0px 5px 5px #229abf; }
const toggleCheckbox = document.querySelector('.toggle-switch-semantic input'); const toggler = document.querySelector('.toggle-switch'); const switchStatus = document.querySelector('.status'); let switchIsActive = false; // Вызывается всякий раз, когда вы нажимаете на переключатель function handleChange() { // Заставляет страницу переключаться между светлым и темным режимом document.body.classList.toggle('dark-mode'); // Вызывает тумблер, чтобы изменить внешний вид toggler.classList.toggle('active'); // Изменяет содержание статуса switchIsActive = !switchIsActive; switchStatus.innerHTML = switchIsActive ? 'on' : 'off'; } toggleCheckbox.onchange = handleChange;
Почему мы должны использовать семантическую разметку вместо ARIA? Вот несколько причин:
Мне действительно нравится, как выразилась Кэтлин МакМэхон. Если веб-разработка похожа на приготовление пищи, то семантические элементы — это ваши высококачественные ингредиенты. Атрибуты ARIA — это ваши приправы. Готовьте с ними, во что бы то ни стало, но вам нужно только небольшое их количество.
Если вы хотите узнать больше об ARIA, я рекомендую следующие ресурсы:
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…
View Comments
Одна из лучших статей по этой теме, спасибо
Если ваши ярлыки не работают, убедитесь, что у вашего элемента есть landmark role или роль, которая подразумевает интерактивность.
Спасибо!!! 8 часов поиска проблемы и теперь работает :)
Статья супер, очень мало хорошего материала по данной тематике