Будущее доступности для пользовательских элементов
Когда пользователи вспомогательных технологий, таких как программы чтения с экрана, перемещаются по веб-странице, жизненно важно передать семантическое значение различных элементов управления.
Например, если программа чтения с экрана посещает кнопку входа в систему:
<button>Sign in</button>
- сообщалось: «Войдите, кнопка». Это сообщает пользователю о доступных ему аффордансах - например, является ли что-то кнопкой, которую можно нажать, или это просто блок текстового контента без какой-либо другой семантики.
Кроме того, встроенные элементы поддерживают использование клавиатуры, что важно для пользователей, которые не могут использовать указывающее устройство - независимо от того, не видят ли они указатель или не обладают физическими возможностями. Вот почему эксперты по доступности всегда призывают разработчиков размечать свои страницы встроенными элементами.
Пользовательские элементы, напротив, не имеют неявной семантики или поддержки клавиатуры.
Когда вы определяете новый тег, браузер действительно не имеет возможности узнать, пытаетесь ли вы создать кнопку, слайдер или просто необычный текстовый контейнер. Добавление этих функций обратно требует от разработчика изрядной работы, и может быть трудно достичь паритета с нативными эквивалентами.
‹Howto-component›
Недавно мы запустили проект под названием HowTo: Components, который демонстрирует, как создавать доступные пользовательские элементы. Многие люди с тех пор спрашивали нас, почему мы пытаемся реализовать такие вещи, как checkbox, если уже существует доступная нативная версия.
Даже беглый взгляд на любую веб-платформу показывает, что разработчики продолжают создавать настраиваемые флажки, хотя это, возможно, больше работы, чем использование встроенного элемента. Мы скоро поймем, почему это так, но, учитывая это, мы хотели бы обучить разработчиков лучшим практикам для этого. Здесь мы черпаем вдохновение из Руководства по методам разработки ARIA, и фактически все HowTo: Components основаны на их примерах. Мы просто хотим проиллюстрировать, как сделать их как пользовательские элементы.
Итак, почему разработчики продолжают изобретать это колесо?
Встроенные элементы отличные. Пока вы не попытаетесь их стилизовать.
<input>
похож на швейцарский армейский нож элементов. Он содержит несколько разных типов (текст, дата, файл ...), и каждый из них сложно стилизовать. Вы когда-нибудь пробовали стилизовать <input type="file">
? Это отстой. Вот как Марк Отто, соавтор Bootstrap, рекомендует стилизовать их на своем сайте wtfforms:
Файловый ввод - самый сложный из всех. Вот как это работает:
- Мы оборачиваем
<input>
в<label>
, чтобы пользовательский элемент управления правильно запускал файловый браузер. - Мы скрываем файл по умолчанию
<input>
черезopacity
. - Мы используем
:after
для создания настраиваемого фона и директивы (Выберите файл ...). - Мы используем
:before
для создания и размещения кнопки «Обзор». - Мы объявляем высоту
<input>
для правильного размещения окружающего содержимого. - Мы добавляем явный текст метки для вспомогательных технологий с атрибутом
aria-label
.
Другими словами, это полностью настраиваемый элемент, созданный с помощью CSS.
Не смешно. Я думаю, что большая причина того, что так много сайтов недоступно, заключается в том, что разработчики сталкиваются с этими ограничениями стиля и решают просто свернуть свои собственные элементы управления - без добавления необходимой семантики и поддержки клавиатуры.
Так почему же так сложно стилизовать встроенные элементы формы? Разве браузеры не могут сделать это так же просто, как стилизовать <div>
или <h1>
?
Не совсем. Такие элементы, как <input>
и <select>
, не всегда реализуются в виде обычных элементов DOM. Иногда это так, поэтому есть статьи о хитростях CSS для стилизации <input type="range">
. В других случаях они обрабатываются непосредственно операционной системой - поэтому появляется стандартный <select>
, похожий на любой другой собственный раскрывающийся список на платформе, которую вы используете. Они заданы как своего рода черный ящик, что означает, что браузер должен определить их внутреннее устройство, поэтому выявить для них стилистические хуки довольно сложно и часто очень ограниченно. Вполне возможно, что мы никогда не сможем стилизовать эти элементы в желаемой степени.
Альтернативой является раскрытие магического поведения этих элементов в виде новых API веб-платформы. Это не только позволит нам создавать более гибкие версии <input>
и <select>
, но мы также сможем расширить грамматику, включив в нее другие элементы, такие как <multi-select-autocomplete-thing>
.
Вот почему я так увлечен кастомными элементами. На мой взгляд, именно здесь живет будущее доступности. Я очень хочу прекратить взламывать CSS поверх <select>
. Я хочу создать свои собственные крутые, расширяемые, стилизованные и доступные элементы, не уступающие по качеству встроенным!
Я надеюсь, что помимо моделирования передовых практик с помощью современных технологий, HowTo: Components поможет нам определить области, в которых мы можем создавать более совершенные API для следующего поколения веб-технологий. Мы хотим подойти к моменту, когда нам не придется выбирать между невыполнимой задачей стилизации существующего набора встроенных элементов или неудобной, подверженной ошибкам и в значительной степени забытой работой по повторной реализации доступности для каждого нового пользовательского интерфейса. элемент.
Как нам туда добраться?
Первый шаг - убедиться, что наши настраиваемые элементы имеют правильную семантику.
Я очень рад возможности нового предложения Объектная модель доступности (AOM), которое поможет нам в этом. AOM позволяет элементу определять свою семантику непосредственно в дереве доступности.
Вы спросите, что такое дерево доступности? Ага! У нас для вас есть статья!
Как я упоминал ранее, пользовательский элемент, семантически говоря, представляет собой просто <span>
, тогда как собственный элемент <button>
имеет встроенную доступность, поскольку он выполняет неявную роль «кнопки». Хотя мы могли бы использовать атрибуты ARIA <custom-button>
sprout для определения его семантики, это может быстро стать уродливым. Чтобы воссоздать <input type="slider">
в качестве настраиваемого элемента, в конечном итоге будет выглядеть так:
А поскольку ARIA - это исключительно API атрибутов HTML, это означает, что нам нужно касаться DOM каждый раз, когда мы хотим обновить наше семантическое состояние. Для отдельного элемента это не так уж плохо, но если у вас есть сотни элементов управления (возможно, внутри таблицы или списка), то, если каждый из них будет вызывать setAttribute()
несколько раз при запуске, это может привести к снижению производительности.
С помощью AOM ваш элемент может просто определить свою семантику в своем конструкторе следующим образом:
- и потребитель вашего элемента не должен видеть, как атрибуты растут повсюду. Фактически, <input type="slider">
и <custom-slider>
становятся неразличимы на семантическом уровне.
Некоторые даже предлагали предоставить настраиваемым элементам доступ к специальному «частному» accessibleNode
, чтобы автор мог определять неизменяемую семантику по умолчанию. Это будет означать, что можно безопасно переопределить роль элемента, затем удалить это переопределение, и все будет безопасно. Например:
Но подождите, есть еще кое-что ...
Другой серьезной проблемой использования ARIA является тот факт, что все отношения должны определяться с использованием ссылок на идентификаторы. В многочисленных проектах мне приходилось автоматически генерировать уникальные идентификаторы, чтобы эта система работала:
Кроме того, новые стандарты, такие как Shadow DOM, устанавливают границы области видимости для идентификаторов. Если вам нужно указать aria-labelledby
или aria-activedescendant
на что-то по другую сторону этой теневой границы, вам не повезло!
AOM исправляет это, позволяя строить отношения, используя ссылки на объекты. В приведенном выше примере мы могли бы переписать наш список с помощью:
accessibleNodes
в приведенном выше примере просто происходит от ссылки на другие элементы на странице. Больше никаких сгенерированных идентификаторов или загромождения DOM. Отлично!
Подождите, разве не было чего-то, что называется is = "" для пользовательских элементов?
Встречное предложение добавить всю эту семантику самостоятельно - просто унаследовать от встроенных элементов. Для нестандартных элементов эта идея была обозначена как настраиваемые встроенные модули. С помощью настраиваемых встроенных модулей вы можете наследовать что-то вроде HTMLInputElement, а затем делать <input is=”custom-checkbox”>
.
К сожалению, настраиваемые встроенные модули не вошли во все браузеры, в основном потому, что они страдают от нескольких серьезных проблем. Главный из них заключается в том, что если вы унаследуете от другого элемента, такого как <select>
, и добавите свой собственный теневой корень, он уничтожит все стили и поведение элемента по умолчанию. Поскольку основная причина, по которой вы изначально расширяли элемент, вероятно, заключалась в его стилизации, это просто создает больше проблем.
Я думаю, что в ближайшем будущем новые примитивы, такие как AOM и пока еще не определенный обратный вызов отправки формы, предложат лучшую альтернативу, когда дело доходит до репликации встроенных элементов. Поскольку для пользовательских элементов по-прежнему требуется JavaScript для загрузки, все еще остаются нерешенными вопросы о прогрессивном улучшении, но я надеюсь, что все большее раскрытие примитивов поможет нам найти другие способы решения этой проблемы.
Подведение итогов
Это не совсем заботы о пользовательских элементах. На самом деле, любой компонент (React, Angular и т. Д.) Должен получать выгоду от таких предложений, как AOM. Но настраиваемые элементы - это единственный основанный на стандартах способ определить компонент, который может использоваться совместно фреймворками, поэтому решение задач на этом уровне кажется очень полезным.
Наш план с HowTo: Components состоит в том, чтобы продолжать создавать собственные эквиваленты элементов встроенных модулей, чтобы мы могли обучать разработчиков и продвигать эти стандарты. Мы также обновим документацию, чтобы явно указать на ограничения, с которыми в настоящее время сталкиваются пользовательские элементы, а использование встроенных функций может иметь больше смысла. Мы хотели бы помочь использовать все примеры ARIA Authoring Practices в качестве настраиваемых элементов и планируем продвигать вещи еще дальше в будущих кварталах, исследуя более сложные типы виджетов. Если вы заинтересованы в участии, не стесняйтесь открывать пул реквест на HowTo: Components repo, а если вы хотите узнать больше об AOM, вы можете проверить его в репозитории Web Incubation Community Group .
Большое спасибо Alice Boxhall, Matt Gaunt и Surma за рецензирование этого сообщения в блоге.
Первоначально опубликовано на сайте robdodson.me 2 октября 2017 г.