От создателя: в моей работе в качестве консультанта по доступности я нередко сталкиваюсь с неуввязками на веб-сайтах. В крайнее время весьма нередко встречается то, что люди делают элементы выбора для форм. Я могу сказать, что они пробуют создать их доступными, поэтому что добавляют атрибуты ARIA либо зрительно сокрытые аннотации для юзеров программ чтения с экрана. Время от времени они употребляют плагин, создатели которого говорят, что он доступен. И это здорово, мне нравится, что люди желают поступать верно! Но до сего времени я никогда не сталкивалась с пользовательским элементом выбора, который по сути соответствует всем аспектам WCAG AA.
Нередко я рекомендую людям употреблять select заместо этого пользовательского элемента HTML. Да, они супер уродливые, но их еще проще стилизовать, чем ранее. Они характеризуются почти всеми функциями доступности — распознаются и верно объявляются всеми программками для чтения с экрана, они накрепко и прогнозируемо работают с клавиатурой и сенсорным экраном и отлично смотрятся в высококонтрастных темах.
Но время от времени я не могу советовать элемент select в качестве подмены. Мы желаем, чтоб кто-то мог избрать элемент из перечня вариантов, но это труднее, чем кажется. Нам необходимо автозаполнение вариантов. Мы желаем поместить туда изображения, а не попросту текст. Элемент optgroup некрасив, его тяжело стилизовать, и он не объявляется программками для чтения с экрана. Стили фокуса малоконтрастны. Я ложила огромные надежды на элемент datalist, но хотя он отлично работает с программками для чтения с экрана, он не подступает для людей с нехорошим зрением, которые масштабируют окно либо употребляют высококонтрастные темы.
Набросок 1: datalist с повышением 300%
Элемент select ограничен в почти всех отношениях. С ними трудно работать, когда у вас есть то, что смотрится практически так, как вы желаете, но очень ограничено, чтоб быть полезным. Мы знаем, что можем достигнуть большего, потому мы создаем пользовательские элементы.
Давайте разберемся, как это создать, сохранив все особые способности оригинала.
Семантический HTML
Мы начнем с семантической базы HTML. На самом деле select — это элемент ввода текста, который ограничивает вероятные ответы, потому давайте сделаем обычный элемент.
User Type
12 | User Type |
Потом нам необходимо показать всем, кто может созидать, что есть доступные варианты, потому давайте добавим изображение со стрелкой, как в нативном элементе.
User Type
123 | User Type |
Для этого элемента мы будем употреблять атрибуты ARIA для представления инфы в иконке, потому мы зададим пустой атрибут alt, чтоб программки чтения с экрана не объявляли название файла.
В конце концов, нам нужен перечень вариантов. Элемент неупорядоченного перечня — разумный выбор. Это также дозволяет программкам для чтения с экрана осознавать, что эти фрагменты текста соединены вместе как часть группы.
1234567 |
Вы сможете динамически добавлять либо удалять варианты из этого перечня, когда для вас необходимо. И, в отличие от элемента option снутри select, мы можем добавить снутри элемента перечня все, что захотим. Так что, если для вас необходимы изображения, чтоб различать огромное количество объектов с весьма схожими именами либо добавлять доп детали, вы сможете пойти далее. Я собираюсь добавить доп текст, чтоб посодействовать разъяснить различия меж вариациями.
Это отменная база для начала. Но это не похоже на элемент select! Мы желаем, чтоб наши зрячие юзеры получили что-то, с чем они уже знакомы и знают, как это употреблять.
Использование Gutenberg улучшает показатели Gore Web Vitals сайта
Стилизация при помощи CSS
Я добавлю несколько главных стилей, схожих на те, что описаны в статье Скотта Джела выше.
Мы также должны обеспечить, чтоб люди, которые настраивают цвета в высококонтрастных режимах, по прежнему могли сказать, на что они глядят. Опосля проверки этого в обычной высококонтрастной теме Windows я решила добавить левую рамку к стилям фокуса и наведения, чтоб было ясно, какой элемент будет избран.
На данный момент также можно добавить стили темного режима. Люди, которые испытывают мигрени от ярчайших экранов, будут для вас признательны!
JavaScript для поведения
Естественно, наш обычай select практически не делает еще ничего. Для этого у нас есть несколько задач: переключать перечень вариантов, открывать и закрывать элемент, когда мы кликаем по нему, фильтровать варианты, когда люди вводят данные, и выбирать вариант, чтоб добавить его и закрыть перечень. Поначалу я собираюсь заняться переключением, поэтому что это проще всего.
Переключение
Время от времени люди употребляют opacity либо height, чтоб скрыть контент на дисплее, но это похоже на внедрение плаща-невидимки Гарри Поттера. Никто не может созидать, что там, но Гарри не перестает существовать, и вы все равно сможете ткнуть его палочкой. В нашем случае юзеры программ чтения с экрана и клавиатуры могут как и раньше получать доступ к невидимому списку.
Заместо того, чтоб создать контент прозрачным либо наименьшим, я собираюсь употреблять display: none, чтоб скрыть перечень. display: none удаляет контент из дерева особых способностей, чтоб к нему не мог получить доступ ни один юзер, а не только лишь те, кто его не лицезреет. У меня постоянно есть пара служебных классов для сокрытия вещей:
CSS .hidden-all { display: none;
}
.hidden-visually { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; -webkit-clip-path: inset(50%); clip-path: inset(50%); border: 0;
}
12345678910111213141516 | .hidden-all { display: none;} .hidden-visually { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; -webkit-clip-path: inset(50%); clip-path: inset(50%); border: 0;} |
Так что сейчас я могу просто переключать класс CSS .hidden-all в перечне, когда захочу.
Просмотр вариантов
Открытие перечня отлично работает для юзеров мыши и сенсорных устройств. Наши стили делают приятную огромную цель касания, и юзеры мыши могут кликать там, где им нравится.
Мы должны также позаботиться о юзерах клавиатуры. Некие из зрячих юзеров будут полагаться на клавиатуру, если у их возникнут трудности с подвижностью либо ловкостью. Обычно юзеры программки чтения с экрана находятся в режиме просмотра, который дозволяет им жать клавиши со стрелками для навигации по контенту. Но пользовательские элементы select обычно находятся снутри частей формы, которые переводят программное обеспечение для чтения с экрана в режим форм. В режиме форм программное обеспечение для чтения с экрана может получать доступ к выделенным фокусом элементам, лишь когда юзер надавливает кнопку Tab, если лишь мы не предоставим кандидатуру. Наши элементы перечня по дефлоту не фокусируемы, потому давайте поработаем над данной для нас кандидатурой.
Для этого я добавляю tabindex -1 к любому элементу перечня. Таковым образом, я могу задать им выделение фокусом при помощи JavaScript, но они не будут частью обыденного пути выделения фокусом клавиатуры на страничке.
JavaScript csOptions.forEach(function(option) { option.setAttribute(‘tabindex, ‘-1’)
})
123 | csOptions.forEach(function(option) { option.setAttribute(‘tabindex, ‘-1’)}) |
Сейчас я могу перемещать фокус при помощи кнопок со стрелками , также при помощи мыши либо касания экрана. Свойство документа activeElement является методом поиска, где на этот момент находится фокус клавиатуры. Я могу употреблять это для повторяющегося перемещения по элементам в перечне и перемещения точки фокусировки вперед либо вспять, зависимо от того, какая кнопка нажата.
7 функций JavaScript, которые нужно знать, прежде чем изучать React
JavaScript function doKeyAction(whichKey) { const focusPoint = document.activeElement switch(whichKey) { case: ‘ArrowDown’: toggleList(‘Open’) moveFocus(focusPoint, ‘forward’) break case: ‘ArrowUp’: toggleList(‘Open’) moveFocus(focusPoint, ‘back’) break }
}
12345678910111213 | function doKeyAction(whichKey) { const focusPoint = document.activeElement switch(whichKey) { case: ‘ArrowDown’: toggleList(‘Open’) moveFocus(focusPoint, ‘forward’) break case: ‘ArrowUp’: toggleList(‘Open’) moveFocus(focusPoint, ‘back’) break }} |
Выбор
Кнопка Enter является обычным вариантом для активации элемента, и мы желаем, чтоб это соответствовало нативному элементу выбора. Добавим очередной фрагмент…
JavaScript case ‘Enter’: makeChoice(focusPoint) toggleList(‘Shut’) setState(‘closed’)
break
12345 | case ‘Enter’: makeChoice(focusPoint) toggleList(‘Shut’) setState(‘closed’) break |
… потом сделайте функцию, которая захватывает текущий выделенный фокусом элемент и помещает его в текстовый элемент. Потом мы можем закрыть перечень и переместить фокус ввысь.
JavaScript function makeChoice(whichOption) { const optionText = whichOption.documentQuerySelector(‘strong’) csInput.value = optionText
}
1234 | function makeChoice(whichOption) { const optionText = whichOption.documentQuerySelector(‘strong’) csInput.value = optionText} |
Фильтрация
Обычные элементы select имеют сочетания кнопок — при вводе буковкы фокусом будет выделен 1-ый вариант, который начинается с данной для нас буковкы. Если вы наберете буковку снова, фокус переместится на последующий вариант, начинающуюся с данной для нас буковкы.
Это полезно, но тут нет подсказки, чтоб сказать юзерам, сколько вариантов быть может в данной для нас группы, потому они должны экспериментировать, чтоб узнать это. Мы можем сделать лучше опыт юзеров, отфильтровав лишь набор вариантов, соответственный данной для нас буковке либо последовательности букв. Потом зрячие юзеры сумеют буквально выяснить, сколько вариантов у их есть, и продолжить фильтрацию, вводя остальные буковкы, если захочут. (Юзеры программки чтения с экрана не могут созидать оставшиеся варианты, когда набирают текст, но не беспокойтесь — у нас будет решение для их в последующем разделе).
Я собираюсь употреблять способ .filter для сотворения новейшего массива, который содержит лишь те элементы, которые соответствуют текстовому значению ввода. Есть различные методы создать это — моя цель состояла в том, чтоб избежать использования постоянных выражений, но для вас стоит избрать хоть какой способ, который идеальнее всего подступает для вашего контента.
JavaScript function doFilter() { const terms = csInput.value const aFilteredOptions = aOptions.filter(option => { if (option.innerText.toUpperCase().startsWith(terms.toUpperCase())) { return true } }) // hide all options csOptions.forEach(option => option.style.display = «none») // re-show the options which match our terms aFilteredOptions.forEach(function(option) { option.style.display = «» })
}
1234567891011121314 | function doFilter() { const terms = csInput.value const aFilteredOptions = aOptions.filter(option => { if (option.innerText.toUpperCase().startsWith(terms.toUpperCase())) { return true } }) // hide all options csOptions.forEach(option => option.style.display = «none») // re-show the options which match our terms aFilteredOptions.forEach(function(option) { option.style.display = «» })} |
Непревзойденно! Это смотрится и ведет себя весьма отлично. У нас еще есть одна неувязка — для юзера программки чтения с экрана это хаотичная информация. Что сообщается API доступа браузера, так это то, что есть ввод, за которым следует некий кликабельный текст. Они соединены? Непонятно! Что произойдет, если мы начнем вводить текст либо нажмем один из кликабельных вариантов? Это загадка, когда ты не видишь, что происходит. Но мы можем это поправить.
ARIA
Атрибуты ARIA не предоставляют много доп способностей. Добавление атрибута aria-expanded=’true’ по сути ничего не расширяет. Что ARIA делает, так это предоставляет информацию о том, что происходит с API доступности, который потом может передать ее хоть какой вспомогательной технологии, которая запрашивает это.
Требования WCAG молвят нам, что когда мы создаем пользовательские элементы, нам необходимо убедиться, что в целом виджет докладывает нам свое имя, свою роль и текущее значение. И Chrome, и Firefox открывают дерево особых способностей в инструментах разраба, потому вы сможете проверить, как будет отображаться хоть какой из ваших виджетов.
У нас уже есть имя для элемента ввода — оно происходит от метки, которую мы связали с элементом в самом начале. Нам не надо именовать всякую другую часть поля, потому что тогда кажется, что находится наиболее 1-го элемента ввода. Нам также не надо добавлять значение, поэтому что когда мы избираем элемент из перечня, он добавляется к текстовому вводу и, как следует, предоставляется API.
Сравнение и объяснение всех единиц измерения CSS
Но программки чтения с экрана объявят этот пользовательский виджет выбора в качестве поля ввода текста, с некими изображениями и перечнем рядом с ним.
На веб-сайте ARIA Authoring Practices есть шаблон для комбинированных списков с прикрепленными перечнями. Он предоставляет все, что необходимо, чтоб программка для чтения с экрана отдала полезное описание нашего пользовательского виджета.
Я собираюсь добавить весь этот ARIA через JavaScript, заместо того, чтоб поместить его в HTML. Если JavaScript по какой-нибудь причине не работает, элемент быть может обычным текстовым полем, и мы не желаем, чтоб программки чтения с экрана объявляли его наиболее презентабельно.
JavaScript csSelector.setAttribute(‘role’, ‘combobox’) csSelector.setAttribute(‘aria-haspopup’, ‘listbox’) csSelector.setAttribute(‘aria-owns’, ‘#list’) csInput.setAttribute(‘aria-autocomplete’, ‘both’)
csInput.setAttribute(‘aria-controls’, ‘list’)
12345 | csSelector.setAttribute(‘role’, ‘combobox’) csSelector.setAttribute(‘aria-haspopup’, ‘listbox’)csSelector.setAttribute(‘aria-owns’, ‘#list’) csInput.setAttribute(‘aria-autocomplete’, ‘both’)csInput.setAttribute(‘aria-controls’, ‘list’) |
Последующее, что необходимо создать, это сказать слепым юзерам, открыт ли либо закрыт перечень. Для данной для нас задачки я собираюсь добавить в группу атрибут aria-expanded и обновлять его значениями false либо true всякий раз, когда перечень меняет состояние в функции переключения.
Крайний штришок — добавить в виджет секретное сообщение о статусе. Мы можем употреблять его для обновления количества доступных вариантов опосля того, как мы отфильтровали их, введя данные в поле ввода. Когда есть много вариантов для выбора, это помогает людям, которые не лицезреют перечень, сокращая его и давая знать, на правильном ли они пути либо нет. Для этого нам необходимо поначалу указать сообщение статуса в HTML.
1 |
Я использую стиль visually-hidden, чтоб его могли отыскать лишь юзеры программки чтения с экрана. Я использую aria-live, так что он будет объявляться тогда же, когда обновляться, а не только лишь тогда, когда юзер программки чтения с экрана проходит его. Активные области должны находиться при загрузке странички, но нам нечего сказать о пользовательском элементе выбора, потому мы можем пока бросить его пустым.
Потом мы добавляем одну строчку в функцию фильтрации, чтоб отыскать длину текущего перечня.
JavaScript updateStatus(aFilteredOptions.length)
1 | updateStatus(aFilteredOptions.length) |
Потом мы отправляем это в функцию, которая будет обновлять текущую область.
JavaScript function updateStatus(howMany) { console.log(‘updating status’) csStatus.textContent = howMany + » options available.»
}
1234 | function updateStatus(howMany) { console.log(‘updating status’) csStatus.textContent = howMany + » options available.»} |
Заключение
Давайте разглядим, что мы сделали, чтоб сделать хороший пользовательский элемент выбора:
Употребляли семантический HTML, чтоб его было просто интерпретировать при помощи вспомогательных технологий при расширении типов контента, которые мы можем включить в него
Добавили стили CSS, которые довольно размеренны, чтоб нормально работать в разных зрительных средах, также соответствуют нашим потребностям в брендинге
Употребляли JavaScript, чтоб обеспечить базисный функционал нативного элемента
Добавили доп JavaScript для получения полезного функционала, которого не хватает уникальному элементу
Добавили атрибуты ARIA, чтоб обеспечить, чтоб цель и результаты использования элемента были доступны вспомогательным технологиям и обновлялись по мере взаимодействия юзера с ним.
Вы сможете поглядеть мой пользовательский шаблон элемента выбора на GitHub — я буду заносить дополнения по мере тестирования его на остальных вспомогательных разработках, и буду рада предложениям по улучшению.
Шаблон ARIA, описанный чуть повыше, имеет огромное количество примеров и опций. Я надеюсь, что пошаговое выполнение этого примера покажет для вас, для что существует каждое из требований и как вы сможете создать так, чтоб они соответствовали вашим потребностям.
Создатель: Julie Grundy
Редакция: Команда webformyself.
Источник
Вам также может понравиться