HTML и CSS ошибки, влияющие на доступность. Мой опыт и моего незрячего знакомого Ильи. Часть 7

в 9:00, , рубрики: accessibility, html, ruvds_статьи

HTML и CSS ошибки, влияющие на доступность. Мой опыт и моего незрячего знакомого Ильи. Часть 7 - 1

Хабр, я снова пришёл к вам с практическими советами про доступность вместе с Ильей. Мы показываем, как HTML и CSS могут улучшить или ухудшить её. Напоминаю, что Илья мой незрячий знакомый, который помогает мне найти наши косяки в вёрстке.

Сегодня мы рассмотрим следующие аспекты:

  • К чему приводят распространённые ошибки с элементом <label>;
  • Лучший лайфхак с inputmode="numeric" улучшающий мою жизнь;
  • Как пользователи скринридера понимают, что модальное окно открыто.

Давайте начнём!

▍ Что может пойти не так при использовании элемента <label>

Каждое поле ввода должно иметь связанный с ним элемент <label>. Данная мысль есть в подавляющем большинстве статьёй о доступности. Мне, конечно, не хочется дублировать то, что вы уже, скорее всего, прочитали. Что ещё можно добавить?

По моему мнению не хватает описания бытовых проблем, к которым приводит некорректная работа с элементом <label>. Хорошо, что я знаком с Ильёй. Он мне всё рассказал. Теперь я могу передать существующие проблемы вам.

Начнём мы с примера, где добавили элемент <input> без элемента <label>.

<body>
  <form>
    <!-- Элементы формы --->
    <div class="field">
      <input type="text" class="field__input">
    </div>
    <!-- Элементы формы --->
  </form>
</body>

Сейчас скринридеры найдут поле для ввода, но для них оно безымянное. Я спросил Илью, что он делает в такой ситуации:

«Если нет лейбла, то при табуляции с предыдущего поля на следующее ридер не читает его название. Чтобы понять, что я должен делать с таким неназванным полем, мне нужно нажать клавишу Esc, выйти из состояния ввода и вернуться стрелкой на шаг назад, чтобы прочитать название, написанное рядом.»

Первое, что меня заинтересовало в мысли Ильи, что он ищет подсказку перед полем для ввода. Я уточнил у него этот момент.

«Да, это привычка, оставшаяся от олдскульных приёмов реализации, когда названия прямо в полях ещё не встречались. Поэтому интуитивно ищу названия перед. Память от визуального опыта, который у меня тоже есть, подсказывает то же самое.»

Отсутствие элемента <label> у поля, это самая критичная ситуация. А вот если он есть, но несвязан это чуть лучше. Хотя, не намного. Поскольку элемент <label> не связан с полем, то для скринридера поле остаётся безымянным.

<body>
  <form>
    <!-- Элементы формы --->
    <div class="field">
      <label class="field__hint">E-mail</label>
      <input type="email" class="field__input">
    </div>
    <div class="field">
      <label class="field__hint">Телефон</label>
      <input type="text" class="field__input" inputmode="numeric">
    </div>
    <!-- Элементы формы --->
  </form>
</body>

Такой код приводит к тому, что Илья выходит из режима редактирования. Возвращается назад. Если повезёт, то сразу найдёт текст, который с большой вероятностью, но не сто процентной, будет подсказкой. Далее он возвращается к полю для ввода и входит в режим редактирования. Четыре действия вместо одного!

Представим обычную форму регистрации из полей для ввода имени, фамилии, даты рождения, электронной почты и двух полей для ввода и повторения пароля. Пять полей и 20 действий. У тут выбор, смириться или плюнуть на всё это.

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

Когда мы обсуждали позицию подсказки, мне в голову пришёл вопрос: «А что будет в случае, когда подсказка будет находиться после поля ввода, но также не будет связана с ним?»

<body>
  <form>
    <!-- Элементы формы --->
    <div class="field">
      <input type="email" class="field__input">
      <label class="field__hint">E-mail</label>
    </div>
    <div class="field">
      <input type="text" class="field__input" inputmode="numeric">
      <label class="field__hint">Телефон</label>
    </div>
    <!-- Элементы формы --->
  </form>
</body>

Илья назвал этот случай самым неприятным вариантом.

«Самый неприятный для меня вариант, когда названия ставятся после полей. Зрячий может соотнести их правильно, а незрячий соотнесёт текущее название со следующим полем. В результате введёт электронную почту в поле для телефона или что-то подобное.»

Дело не исправляет даже связывание элемента <label> с полем.

<body>
  <form>
    <!-- Элементы формы --->
    <div class="field">
      <input id="email" type="email" class="field__input">
      <label for="email" class="field__hint">E-mail</label>
    </div>
    <div class="field">
      <input id="tel" type="text" class="field__input" inputmode="numeric">
      <label for="tel" class="field__hint">Телефон</label>
    </div>
    <!-- Элементы формы --->
  </form>
</body>

Для понимания проблемы нужно рассказать про нюанс скринридера NVDA. Если он попал на поле ввода с помощью клавиш стрелок, то пользователь услышит: «Редактор». Всё.

То есть на этом этапе неважно есть ли связанная подсказка. Пока пользователь не войдёт в режим редактирования, нажав клавиши Space или Enter, скринридер её не озвучит. По этой причине важна позиция элемента <label>.

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

В итоге самый лучший вариант это использовать связанный с полем элемент <label> перед элементом <input>.

<body>
  <form>
    <!-- Элементы формы --->
    <div class="field">
      <label for="email" class="field__hint">E-mail</label>
      <input id="email" type="email" class="field__input">
    </div>
    <div class="field">
      <label for="tel" class="field__hint">Телефон</label>
      <input id="tel" type="text" class="field__input" inputmode="numeric">
    </div>
    <!-- Элементы формы --->
  </form>
</body>

Существует также вариант, добавления элемента <input> в элемент <label>.

<body>
  <form>
    <!-- Элементы формы --->
    <label class="field__hint">
      <span class="field__hint">E-mail</span>
      <input type="email" class="field__input">
    </label>
    <label class="field">
      <span class="field__hint">Телефон</span>
      <input type="text" class="field__input" inputmode="numeric">
    </label>
    <!-- Элементы формы --->
  </form>
</body>

Я лично избегаю данную технику, потому что в сообществе говорили, что есть ситуации, когда скринридеры не определяют связь элементов. По моему мнению лучше использовать вариант с атрибутами for и id.

▍ Атрибут inputmode позволяет мне меньше мучаться

При заполнении форм важным моментом является отображаемая клавиатура. Здесь, конечно, я сужу по себе. Я обладатель пальцев, которые больше чем клавиши на смартфоне. Данный факт усиливается тем, что из-за травмы у меня периодически тремор рук. Как результат, постоянно делаю опечатки.

Я понимаю, что у разработчиков сложная работа. Фреймворки, дедлайны и всё такое. Но, чёрт, почему при вводе численного типа данных мне отображается виртуальная клавиатура с буквами и маленькими цифрами?

Как-то я покупал авиабилеты. Я дошёл до поля для ввода серии и номера паспорта и увидел стандартную виртуальную клавиатуру. Жаль, здесь нельзя передать все мысли. Учитывая мою проблему с руками, я тогда знатно помучался.

Проблема заключается в том, что в коде используется значение text для атрибута type.

<body>
  <label for="id_0746012685254408">Серия и номер</label>
  <input type="text" title="Серия и номер" class="input__text-input" id="id_0746012685254408">
</body>

Отображается клавиатура с русскими буквами и маленькими цифрами

Для ввода текста это нормальный вариант, а для ввода численного типа данных — нет. Мне больше всего обидно, что разработчик этого приложения не подумал использовать специальную виртуальную клавиатуру с большими числами. Тем более делается это просто. Надо допечатать атрибут inputmode и его значение numeric.

<body>
  <label for="id_0746012685254408">Серия и номер</label>
  <input type="text" inputmode="numeric" title="Серия и номер" class="input__text-input" id="id_0746012685254408">
</body>

Поскольку я не могу изменить код с телефона, я вставил фрагмент кода в Codepen и сделал скриншот клавиатуры.

Отображается клавиатура только с цифрами большого размера

Дело на пять секунд. А пользовательский опыт получается в разы лучше!

▍ Открылось ли модальное окно

Модальное окно является элементом интерфейса, который появляется после нажатия по кнопке. Пользователи без ограничений по зрению привыкли видеть, как он появляется. Срабатывает визуальная ассоциация. А как пользователи скринридера понимают, что модальное окно открылось?

Первый момент. Пользователи скринридера знают, что модальное окно по умолчанию не отображается. Далее они взаимодействуют с приложением. Им встречается кнопка. Они нажимают на неё. Если услышат подсказку «Диалог», то она становится сигналом, что модальное окно открыто.

Нам нужно использовать атрибуты role и aria-modal, чтобы весь процесс работал корректно.

<body>
  <div role="dialog" aria-modal="true" class="modal">
    <!-- здесь дочерние элементы модального окна -->
  </div>
</body>

Значение dialog сообщает скринридеру, что элемент является диалогом. Стоп. В интерфейсах же используются диалоги разного типа. Легко запутаться. Что делать? Здесь на помощь приходит значение true. Именно оно делает элемент модальным окном.

Данная техника использовалась до появления элемента <dialog>. Теперь можно использовать его вместо элемента <div> с атрибутом role.

<body>
  <dialog class="modal">
    <!-- здесь дочерние элементы модального окна -->
  </dialog>
</body>

Важный нюанс. У элемента <dialog> есть два метода для открытия. Это .open() и .showModal(). Для модального окна следует использовать метод .showModal(). В этом случае aria-modal="true" установится автоматически.

▍ Заключение

С помощью этой статьи я с Ильёй хотел призвать вас:

  • Добавлять к каждому полю для ввода информации подсказку, размеченную элементом <label> и связанную с ним;
  • Не важно, где внешне отображается подсказка для поля ввода данных, в коде она должна быть строго перед элементом <input>;
  • Связать элемент <label> лучше стоит через атрибуты for и id;
  • Отображать пользователю более удобную для него виртуальную клавиатуру;
  • Использовать элемент <dialog> для разметки модальных окон.

Оставлю ссылки на все выпуски:

Также нам будет интересен и ваш опыт. Делитесь своими кейсами в комментариях. Спасибо за чтение.

P.S. Если вы хотите больше узнать о цифровой доступности, пишите мне в ТГ. Ссылка в профиле.

Автор: Стас Мельников

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js