Доступные сообщения валидации формы с помощью ARIA и Vue.js
В этой статье вы узнаете, как использовать ARIA и Vue.js, чтобы сделать сообщения об ошибках валидации формы и инструкции доступными для пользователей с ограниченными возможностями.
Как программы чтения с экрана перемещаются по формам и читают их
Разработчик должен понимать различия между тем, как зрячий пользователь взаимодействует с формой, и как воспринимает ее пользователь программы чтения с экрана. Они используют «скрытое» измерение веб-страницы, известное как «дерево доступности». Accessibility tree - это структура, которая позволяет программам чтения с экрана получать информацию из браузера.
Для навигации по веб-форме программное обеспечение для чтения с экрана используют режим, известный как «форма» или «фокус». Этот режим позволяет пользователю перемещаться по интерактивным элементам управления формой с помощью клавиатуры. Когда в фокус попадает элемент управления, программа чтения с экрана считывает поле ввода и связанную с ним метку.
Доступ к сообщениям об ошибках и инструкциям
А как насчет доступа к сообщениям об ошибках валидации или инструкций для полей? Если поместить их в элемент, который не может быть выделен фокусом ввода (например, <div>
или <p>
), то программа чтения с экрана пропустит их. Как это исправить?
Способ 1: Что содержится в имени?
Самый простой способ обеспечить доступность сообщений об ошибках валидации - сделать их дочерними элементами относительно <label>.
Сделав сообщение об ошибке являются частью label, оно становится доступным через элемент ввода. Оно будет прочитано, когда элемент управления попадет в фокус ввода.
Для этого используется директива Vue v-show. Она скрывает сообщение, пока не возникнет ошибка валидации. В том числе и от программ чтения с экрана.
Способ 2: Использовать aria-describedby
Но что, если нужно, чтобы в элементе <label>
не было сообщений об ошибках? В таком случае лучше использовать атрибуты ARIA. Они влияют на то, как экранные дикторы интерпретируют страницы по дереву доступности.
ARIA предоставляет атрибут, который позволяет разработчикам связать другие HTML-элементы с полями формы - aria-describedby
. Для предоставления инструкций для поля формы добавьте к нему атрибут aria-describedby
с id
каждого элемента, который вы хотите связать с input
.
<label for="first_name">First Name:</label>
<input id="first_name" type="text" aria-describedby="first_name-instructions">
<div id="first_name-instructions">maximum length 30 characters</div>
Теперь, когда мы явно связали дополнительные инструкции с полем, добавим сообщения об ошибках:
<div id="first_name-error">
Please enter a valid project name.
</div>
<label for="first_name">First Name:</label>
<div id="first_name-instructions">maximum length 30 characters</div>
<input id="first_name" name="first_name" type="text" aria-describedby="first_name-instructions first_name-error">
С помощью одного простого атрибута мы добавили сообщение об ошибке и связали его с полем формы.
Vue.js упрощает реализацию
Теперь нужно добиться, чтобы сообщение об ошибке не отображалось и читалось постоянно, а только когда возникла ошибка. Для этого мы используем библиотеку Vuelidate.
<div id="first_name-error" v-show="first_name.$error">
Please enter a valid project name.
</div>
<label for="first_name">First Name:</label>
<div id="first_name-instructions">maximum length 30 characters</div>
<input id="first_name" name="first_name" type="text" v-model="$v.first_name.$model" :aria-invalid="$v.first_name.$invalid" aria-describedby="first_name-instructions first_name-error">
Теперь у нас есть сообщение об ошибке, которое связано с полем ввода. И оно будет скрыто, если ошибка валидации не произошла.
Но так как мы используем v-show,
то сообщение будет скрыто и от программ чтения с экрана. Здесь мы сталкиваемся с особенностью атрибута aria-describedby
. По умолчанию связанный элемент будет считываться, даже если он будет скрыть.
Поэтому нам нужно сделать aria-describedby
динамическим, чтобы он добавлял идентификатор сообщения об ошибке только тогда, когда она возникла. Это просто реализовать благодаря Vue.js:
signup-form.html
<div id="first_name-error" v-show="first_name.$error">
Please enter a valid first name
</div>
<label for="first_name">First Name:</label>
<div id="first_name-instructions">maximum length 30 characters</div>
<input id="first_name" name="first_name" type="text" v-model="$v.first_name.$model" :aria-invalid="$v.first_name.$invalid" :aria-describedby="describedBy('first_name')">
main.js
methods: {
// генерация связанных с aria-describedby идентификаторов
describedBy(field) {
const inst = `${field}-instructions`
// field.$error - это логическое вычисляемое свойство, возвращаемое Vuelidate
// если возникла ошибка, valErr становится равным идентификатору поля. В противном случае это пустая строка.
const valErr = field.$error
? `${field}-error`
: ''
//обрезаем и заменяем двойные пробелы одиночными
let refString = ` $ {valErr} ${inst}`.replace(/s+/g,' ').trim()
return refString
}
// базовый конструктор сообщений об ошибках
vMessage(v, field) {
let message = ''
let errors = []
if ($v.$error)) {
// получаем тип ошибки из $params Vuelidate
let errorTypeKeys = Object.keys($v["$params"])
// составляем массив ошибок
for (const key of errorTypeKeys) {
if ($v[key] === false) {
errors.push(key)
}
}
//создаем из массива разделенную запятыми строку
let errorString = errors.length > 1
? errors.join(', ')
: errors[0]
// преобразуем в читаемое сообщение
errorString = errorString
.replace('required', 'This is a required field')
.replace('url', 'The url is invalid')
.replace('email', 'The email address is invalid')
.replace('minLength', 'Input does not meet minimum length')
message = `${errorString}.`
}
return messsage
}
}
Теперь у нас есть динамический атрибут aria-describedby
, который связан с выводом метода describedBy()
. Он принимает имя поля в качестве параметра. Затем определяет, является ли ввод поля действительным, и возвращает список идентификаторов.
Если возникла ошибка и <input>
выделен фокусом ввода, то атрибут aria-describedby
будет ссылаться на сообщение об ошибке и на инструкции. В противном случае программа чтения с экрана объявит только инструкции (содержимое <label>
будет зачитано в любом случае).
Некоторые предостережения
Разработчики должны знать, что программы чтения с экрана также отличаются друг от друга. Они могут интерпретировать html или ARIA по-своему, иметь собственные наборы функций. При этом их функционал может различаться при использовании в сочетании с различными браузерами.
Например, и JAWS, и NVDA поддерживают режим формы (фокуса) и aria-describedby. А Voiceover поддерживает атрибут aria-describedby, но у него нет режима фокуса или формы. NVDA наиболее надежно работает с Firefox, а Voiceover - с Safari.
Нужно учитывать, что в дополнение к чтению скрытых связанных элементов, aria-describedby
игнорирует семантику. Он считывает список связанных элементов как непрерывную строку.
Если ваши инструкции и сообщения содержат списки или другие вложенные элементы, семантика будет игнорироваться. Поэтому лучше всего сделать содержимое сообщений об ошибках коротким и простым, а также использовать пунктуацию.
Будущее: aria-errormessage
В конце 2017 года в ARIA 1.1 был добавлен атрибут aria-errormessage
, предназначенный для сообщений об ошибках валидации. Когда атрибут получит поддержку программами чтения с экрана и браузерами, он будет использоваться вместе с aria-invalid
, чтобы обеспечить более согласованный метод считывания сообщений об ошибке.
Тестирование
Единственный способ убедиться в правильной работе формы – это протестировать ее через программу для чтения с экрана.
Дайте знать, что вы думаете по данной теме в комментариях. Мы крайне благодарны вам за ваши комментарии, подписки, дизлайки, лайки, отклики!