Pull to refresh
3037.86
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

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

Level of difficultyEasy
Reading time7 min
Views3.8K

Хабр, я снова пришёл к вам с практическими советами про доступность вместе с Ильёй. Мы показываем, как 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. Если вы хотите больше узнать о цифровой доступности, пишите мне в ТГ. Ссылка в профиле.


Telegram-канал со скидками, розыгрышами призов и новостями IT 💻
Tags:
Hubs:
Total votes 42: ↑42 and ↓0+43
Comments15

Articles

Information

Website
ruvds.com
Registered
Founded
Employees
11–30 employees
Location
Россия
Representative
ruvds