HTML: плохие стороны
Вероятно, вы слышали заявления типа «HTML и так по умолчанию обладает accessibility» или «Не нужно изобретать заново этот абсолютно идеальный элемент управления HTML». Я считаю, что это общие заявления, а не универсальные истины. Веб-разработчикам крайне важно осознавать недостатки платформы, поэтому я решил собрать несколько примеров того, когда у HTML возникают трудности с точки зрения как accessibility, так и usability.
Это неполный список, и он не включает в себя недостатки ARIA. Мне хотелось найти баланс между широко известными проблемами и чаще встречаемыми (но менее известными), а также добавить в список то, что мы воспринимаем, как должное. В каждом из разделов я укажу степень серьёзности проблемы, альтернативные решения и ссылки, по которым можно найти более подробную информацию.
<select multiple>
Давайте начнём с простого. Атрибут multiple
элемента <select>
не стоит использовать практически никогда. Он похож на полную противоположность одиночного <select>
. Единственное, что его оправдывает, так это то, что я пока не встречал этот атрибут ни в одной кодовой базе.
Цитата пользователя программы для чтения экрана (из превосходной статьи Сары Хигли, ссылка на которую приведена ниже):
Это поломанный listbox. Он совершенно поломан, я не вижу, как это можно исправить.
Серьёзность: высокая. Есть большая вероятность того, что большинство ваших пользователей не умеет работать с этим чудовищным элементом управления.
Что использовать вместо: вполне подходящая альтернатива — список чекбоксов; или можно создать собственный listbox с множественным выбором.
Дополнительное чтение: <select> your poison part 2: test all the things (статья Сары Хигли).
<i> (для значков)
Ещё один простой пример для разогрева. Элемент <i>
семантически несущественен, поэтому необязательно «плох», если используется для обычного текстового содержимого. Однако чаще он применяется для шрифтов значков.
В обычной ситуации я бы даже не стал включать его в список, ведь это больше ошибка разработчиков, чем проблема платформы. Однако уже 2024 год, а я по-прежнему встречаю элемент <i>
, используемый с чем-то наподобие FontAwesome. Это проблемно в основном потому, что веб-шрифт используется для замены текстовых символов (которые могут иметь одно значение) на значки (которые никак не связаны с текстовыми символами).В результате этого текстовые символы, даже если они сгенерированы в CSS, становятся частью контента страницы и по умолчанию будут включены в accessibility-дерево. Кроме того, они плохо выглядят, часто (и непредсказуемо ?) ломаются, приводят к другим проблемам с accessibility. Подробнее обо всех этих проблемах можно узнать из поста Тайлера Стика, ссылка на который приведена ниже.
Серьёзность: низкая или средняя. Можно повысить accessibility, исключив его из accessibility-дерева (при помощи aria-hidden
) и задав текстовую альтернативу (при помощи визуально скрытого текста), но элемент всё равно остаётся проблематичным.
Что использовать вместо: SVG! У них хорошая поддержка, и они во многих отношениях лучше. В отличие от шрифтов значков SVG предназначены именно для отображения графики, поэтому из-за них в accessibility-дереве не появится неожиданный текст. Кроме того, их можно применять множеством разных способов, так что вы можете выбирать: встраивать их, использовать спрайты или хранить их внутри CSS (при помощи mask
).
При использовании <svg>
следует применять следующий надёжный паттерн: aria-hidden
вместе с дополнительным алтернативным текстом (который при необходимости можно визуально скрыть). Например, разметка кнопки выглядит так:
<button>
<svg aria-hidden="true"><use href="#heart" /></svg>
<span>Favorite</span>
</button>
Дополнительное чтение: Seriously, Don't Use Icon Fonts (статья Тайлера Стика)
<ul> и <ol>
Невозможно составить список проблемного HTML и не включить в него эти списки.
Я не говорю «не пользуйтесь списками», во многих ситуациях они очень полезны. Но разработчики склонны использовать их слишком активно, часто просто для удаления стилей списков. Иногда мы даже прицепляем к ним роль ARIA (переопределяя таким образом семантику списка), или, хуже того, добавляем дочерние элементы без <li>
для стилизации или чего-то другого (создавая таким образом недопустимую разметку). Во всех таких ситуациях мы теряем все преимущества элементов-списков и потенциально добавляем новые проблемы.
На это чрезмерное использование списков обратили внимание разработчики Safari и начали в некоторых случаях удалять семантику списков; списки, находящиеся снаружи nav
и стилизованные list-style: none
, Safari списками не считает. Хотя намерения у разработчиков были хорошими, это привело к тому, что даже правильно стилизованные списки становятся исключительно визуальными.
Кроме того, у упорядоченных списков тоже есть собственные странности. Браузеры считают номера элементов «визуальными», поэтому при выборе и копировании списка номера не включатся в текстовый элемент буфера обмена. Это нарушает ожидания пользователей, особенно если номера для них важны, например, в случае юридических документов.
Серьёзность: низкая или средняя. Я думаю, что вполне нормально позволить Safari/VoiceOver делать то, что они делают; их пользователи привыкли к этому и даже могут ожидать, что вебе почти не существует списков. Проблема упорядоченных списков и буфера обмена может быть достаточно серьёзной, но её можно решить обходными путями.
Что использовать вместо: если вам сильно нужно сохранить семантику списков, то к <ul>
можно добавить role="list"
. Если вы уже используете другую роль, то вполне подойдут обычные <div>
. Ещё одной потенциальной альтернативой для пар «ключ-значение» может быть <dl>
.
<ul role="list">
<li>…</li>
<li>…</li>
<li>…</li>
</ul>
Если важны номера пунктов списка, то можно попробовать использовать неупорядоченные списки, в которых числа — часть текстового содержимого.
Дополнительное чтение: "Fixing" Lists (статья Скотта О'Хара), пост в Twitter Джеймса Крейга из Apple и "I Blame the W3C's HTML Standard for Ordered Lists" (статья Сибиллы Бостониенсис).
Атрибут title
Атрибут title
напрягает меня больше всех, в частности, из-за его долгой истории. Он настолько плох, что в спецификации HTML прямым текстом не рекомендуют его использовать. Тем не менее, я встречал этот атрибут в каждой кодовой базе, с которой работал.
Вот лишь некоторые из множества проблем title
:
Зрячие клавиатурные пользователи никак не смогут получить доступ к содержимому
title
.Пользователи с сенсорными экранами тоже не могут получить доступ к содержимому
title
.Стандартную стилизацию всплывающих подсказок (tooltip) нельзя изменить никаким способом.
Над триггером нужно держать указатель произвольно долгое время, прежде чем он появится.
Всплывающую подсказку невозможно закрыть без перемещения указателя, поэтому она может закрывать другие части страницы.
На всплывающую подсказку невозможно навести указатель, то есть мышь должна находиться над элементом триггера. Поэтому подсказку может перекрыть курсор мыши, её текст невозможно будет выбрать, а пользователи экранной лупы не смогут просмотреть её.
Текст внутри всплывающей подсказки не масштабируется вместе с пользовательским уровнем зума.
Перенос длинного текста внутри всплывающей подсказки невозможно реализовать; в некоторых браузерах он становится шириной с экран (даже выходя за границы окна браузера), и только потом начинает работать перенос.
Нельзя указать, должно ли содержимое
title
быть частью имени или описания элемента (или ни то, ни другое).Программы для чтения экрана по разному читают содержимое
title
в разных элементах.
Серьёзность: высокая. Используя этот атрибут, вы намеренно выбираете снижение accessibility для большого процента пользователей.
Что использовать вместо: во многих случаях достаточно включить текст в виде части содержимого элемента; при необходимости этот текст может быть визуально скрыт. В других случаях aria-labelledby
или aria-describedby
работают лучше, чем title
. Одно из исключений — это iframe, которые нужно размечать при помощи title
.
Почти во всех случаях, наряду с описанными выше техниками, лучше, чем title
подойдёт собственная всплывающая подсказка. Однако у всплывающих подсказок есть свои проблемы, поэтому ещё лучше будет перепроектировать так, чтобы полностью избавиться от необходимости подсказок. Например, всегда можно отображать текст или использовать паттерн disclosure.
Дополнительное чтение: The Trials and Tribulations of the Title Attribute (статья Скотта О'Хара) и Using the HTML title attribute (статья Стива Фолкнера).
<datalist>
Поначалу элемент datalist
кажется удачной альтернативой собственных комбобоксов. Однако чем больше вы его используете, тем глубже становится разочарование.
Стандартная стилизация элемента крайне сомнительна.
В десктопном Chrome он отображается как странно смещённый всплывающий контейнер (popover), резко меняющий своё местоположение, когда пользователь вводит текст; в то же время он отсоединяется от элемента ввода, когда пользователь прокручивает страницу.
В Chrome под Android он отображается поверх виртуальной клавиатуры (а не на странице) и только в портретном режиме.
Его внешний вид невозможно никак настроить. Он не учитывает даже
color-scheme
.Он не учитывает пользовательский размер шрифта и уровень зума.
В целом он хорошо поддерживается десктопными программами чтения экрана, но на мобильных для взаимодействия с опциями необходимо перейти к самому концу страницы.
В Firefox под Android он вообще не работает!
Серьёзность: средняя или высокая. В лучшем случае, этот элемент может быть полезен как необязательная подсказка полей ввода, которые будут полностью рабочими без дополнительной помощи со стороны опций автоматического завершения.
Что использовать вместо: <select>
или собственный комбобокс.
Дополнительное чтение: Under-Engineered Comboboxen? (статья Адриана Розелли)
<input placeholder>
Текст-заполнитель должен помогать пользователю, давая подсказку, когда поле ввода пусто. На практике он часто выполняет обратную функцию.
Текст-заполнитель обычно подвержен проблемам контрастностью цветов. Если попробовать исправить контрастность цветов, то он может стать неотличимым от реальных вводимых значений. Если поместить в него важную информацию (например, требования к паролю), то вводимое значение скроет эту важную информацию сразу после того, как пользователь начнёт печатать.
Серьёзность: средняя или высокая. В лучшем случае его можно игнорировать. В худшем он может раздражать пользователей и вредить прибыли.
Что использовать вместо: может, ничего? Вполне может быть достаточно заметного label. Если вам нужен текст подсказки, то можно разместить его снаружи поля ввода и связать их при помощи aria-describedby
.
<label for="phone">Phone number</label>
<input id="phone" aria-describedby="phone-hint" />
<div id="phone-hint">Example: 123-456-7890</div>
Дополнительное чтение: Don't Use The Placeholder Attribute (статья Эрика Бэйли)
<input type=number>
Числовые поля ввода выполняют инкремент/декремент при использовании колеса мыши, жестов или клавиш со стрелками, из-за чего крайне вероятны неприятности.
И это в дополнение к другим проблемам с accessibility, согласованностью и стилизацией.
Некоторые браузеры молча игнорируют нечисловой ввод без какой-либо обратной связи.
Другие браузеры позволяют вводить произвольные числа, но запускают события с пустыми значениями, теряя таким образом введённые пользователем данные.
Кнопки со стрелками очень малы и их сложно нажимать.
Кнопки со стрелками невозможно стилизовать (кроме простой цветовой схемы).
Серьёзность: высокая. Чтобы отказаться от элемента, достаточно проблемы со скроллингом, потому что пользователи могут ввести неверное число, даже этого не поняв.
Что использовать вместо: <input inputmode="numeric" pattern="[0-9]*">
. Атрибут inputmode
помогает отображать на устройствах с сенсорным экраном более удобную клавиатуру, а атрибут pattern
помогает с валидацией.
Дополнительное чтение: Why the GOV.UK Design System team changed the input type for numbers
<input type=date>
Нативные элементы выбора даты обладают несогласованностью в браузерах, а некоторые их части нарушают accessibility.
В десктопном Chrome на кнопку календаря невозможно переключиться клавишей Tab.
В десктопном Safari элемент выбора даты невозможно закрыть с клавиатуры.
В десктопном Safari элемент выбора даты имеет крошечный размер и его невозможно увеличить.
В Chrome и Firefox под Android в элемент выбора даты нельзя ничего ввести, поэтому приходится использовать неудобный UI календаря, даже если пользователю известна дата.
Во всех средах формат данных отображается в виде текста-заменителя, который, как мы уже выяснили, вызывает проблемы. Формат даты определяет браузер и он может выбрать что-то странное (например, формат даты США), что приводит к ненужным затруднениям.
Серьёзность: высокая. Эти несогласованности — не просто небольшие неудобства, они создают реальные препятствия для accessibility.
Что использовать вместо: простые поля ввода текста, а в некоторых случаях даже select.
Также можно использовать отдельные поля для дня/месяца/года и сгруппировать их при помощи fieldset. Этот fieldset даже можно стилизовать так, чтобы он выглядел, как одно сплошное поле формы. Однако если вы решите спрятать label поля ввода, то я бы рекомендовал отображать формат даты вне полей ввода (как часть легенды или под полями ввода).
Известно, что собственные элементы ввода даты очень сложно реализовать правильно, поэтому если решите создать их, то они должны быть опциональными и дополнять поля ввода текста.
Дополнительное видео: What makes an accessible date picker? Is it even possible? (доклад Расса Уикли)
<menu>
Просто не пользуйтесь ими. Какого бы поведения вы ни ожидали от этого элемента... вы, скорее всего, ошибётесь. Изначально элемент <menu>
подразумевался как «контекстное меню», но его так и не реализовали, а теперь он заменён <ul>
.
Серьёзность: низкая. <menu>
просто преобразовывается в <ul>
.
Что использовать вместо: так как термин «меню» перегружен значениями, это зависит от того, что вы хотите сделать. Вот некоторые из альтернатив:
<ul>
(илиrole="list"
), если у вас есть список.role="menu"
, если у вас меню в десктопном стиле.role="listbox"
, когда у вас что-то, напоминающее собственный<select>
.<dialog>
илиrole="dialog"
, если у вас стандартный всплывающий контейнер (возможно, сrole="list"
внутри).
Стоит отметить, что некоторые из этих ролей требуют подключения взаимодействий с JavaScript.
Дополнительное чтение: Be Careful Using 'Menu' (статья Адриана Розелли)
<button disabled>
Отключенные кнопки почему-то активно используют, возможно из-за их привычности. Вот два популярных сценария применения отключенных кнопок:
когда действие временно недоступно, например, из-за того, что требуется какая-то обязательная задача (например, выбор элемента или правильное заполнение формы).
при отправке формы, чтобы избежать повторной отправки.
Однако атрибут disabled
не просто предотвращает клики. Он также отключает функции hover и focus. И это имеет множество негативных последствий. Отключенные кнопки не могут отображать всплывающие подсказки (которые могут объяснять, почему кнопка отключена). Клавиатурные пользователи не могут добраться до отключенных кнопок через Tab. Если кнопка внезапно становится отключенной (например, при отправке формы), фокус может потеряться и сбить пользователя с толку. Кроме того, отключенные кнопки освобождаются от требования контрастности цветов, повышая вероятность их плохой контрастности.
Серьёзность: высокая. Отключенные кнопки удобны (да и то не особо) только для небольшого процента пользовательской базы.
Что использовать вместо: aria-disabled="true"
и вручную отключить клики. Однако при возможности переработайте дизайн так, чтобы он не требовал отключенных кнопок.
Дополнительное чтение: Making Disabled Buttons More Inclusive (статья Сандрины Перейра)
<video>
Нативный проигрыватель видео по-прежнему имеет множество проблем с accessibility и usability. Во многих браузерах у клавиатурных пользователей возникает проблема с фокусом, потому что они могут добраться не до всех элементов управления, и эти элементы пропадают после начала воспроизведения видео. В некоторых аспектах он неудобен и для пользователей программ чтения экрана, особенно в случае «продвинутых» функций наподобие режима «картинка в картинке».
Настоятельно рекомендую прочитать приведённую ниже статью Адриана Розелли, чтобы глубже изучить поддержку этого элемента в разных браузерах и программах чтения экрана.
Серьёзность: средняя или высокая.
Что использовать вместо: точно не знаю. Возможно, альтернативный проигрыватель видео, если он разрабатывался с учётом accessibility. Но чем бы вы ни пользовались, не забудьте добавить подписи и транскрипции, а также предоставьте возможность скачивания видео для его просмотра в удобном для пользователя проигрывателе. И ради заботы о пользователях не применяйте autoplay
.
Дополнительное чтение: Browser Video Players Review (статья Адриана Розелли)
Протоколы ссылок (tel:, mailto:)
Ссылки в вебе могут иметь не относящийся к http протокол наподобие mailto:
или tel:
. Эти протоколы активно используют, чтобы помочь пользователям (или спамерам) отправить электронное письмо или набрать номер. Однако очень смело было бы считать, что пользователь заходит на сайт с того же устройства, которое будет использоваться для отправки электронного письма или набора телефонного номера, и что он хочет использовать для этого приложение по умолчанию. Это может привести к раздражению, когда пользователь просто ищет способ скопировать номер или набрать его с другого устройства. Хуже того, адрес почты/номер часто скрывают под ссылкой, отображая вместо него нечто бесполезное типа «Написать мне».
Серьёзность: низкая или средняя. Это раздражает и сбивает с толку, но, наверно, ничего особо страшного в этом нет. Пользователи находят способы решить проблему.
Что использовать вместо: просто покажите реальный адрес почты или телефонный номер. Его можно легко скопировать или вручную перенести на нужное устройство. Кроме того, многие устройства автоматически отображают подсказку при выборе текста, который можно распознать как почту/номер.
Дополнительное чтение: tel:me.about.it. (статья Брайана Кэрделла)
Подведём итог
В завершение хочу повторить, что для реализации accessibility недостаточно «просто использовать HTML». Даже имея самые благие намерения и используя абсолютно правильную разметку HTML, можно создать UI без нужного уровня accessibility, если подойти к делу без усердия.
Я уверен, что через десять лет этот список будет выглядеть иначе (и, надеюсь, станет короче). Чем больше людей будет интересоваться этой темой, тем доступней станет информация. Это заставит органы стандартизации и поставщиков браузеров совершенствовать платформу и приблизить нас к вебу с большей степенью accessibility. Вы лично можете помочь, сообщая о новых багах или комментируя уже найденные: