Примечание: я все еще изучаю доступность, поэтому, если вы найдете недостаток в моем методе, пожалуйста, дайте мне знать в комментариях ниже!
Создать пользовательские компоненты сложно. Вы должны переопределить много стиля браузера по умолчанию, и часто это может быть утомительным. И в некоторых случаях невозможно стилизовать HTML -элементы. Это так с выбранным выпаданием.
Невозможно стилизовать выбранное выпадающее меню, потому что у нас нет возможности обернуть набор <Опция>
Элементы в контейнере (который необходим для абсолютного позиционирования элементов списка против родительского элемента).
Таким образом, мы должны «взломать» наш путь к созданию выпадения. К сожалению, это обычно приводит к отсутствию доступности.
В этом уроке мы узнаем, как создать выбросы настраиваемого выбора, при этом соблюдая стандарты доступности W3C.
Вот выпадение, которое мы будем создавать:
Традиционно, при создании выбора выпадающего вниз, вы будете использовать следующее:
Проблема с использованием Элемент в том, что вы не можете обернуть ребенка
<Опция>
Элементы в контейнере. Зачем нам обернуть эти элементы в контейнер? Чтобы расположить выпадающий список под окном ввода.
В нашем случае мы хотим, чтобы элементы списка, <Опция>
Элементы, которые будут расположены под коробка. Браузер отображает пункты меню по умолчанию в качестве наложения:
Чтобы относительно позиционировать дочерний элемент по отношению к родительскому элементу, так и в случае с пользовательским выпадающим меню, вы должны установить следующие свойства CSS:
.parent { position: relative; } .child { position: absolute; top: 0; left: 0; }
Вы можете задаться вопросом: «Разве вы не можете переписать HTML на следующее (используя CSS выше)?
Ответ, к сожалению, Нет Анкет Вы не можете разместить Внутри
Анкет
Поэтому мы должны создать доступный обходной путь.
Создание пользовательского выбора
Поскольку мы не можем использовать Элемент, я решил использовать серию
и элементы.
Структура выглядит примерно так:
- Label
- Option 1
-
- Option 1
- Option 2
Это довольно просто.
- У нас есть весь компонент, завернутый в неупорядоченный список.
- Метка – это элемент списка.
- Выбор также является элементом списка.
- Затем у нас есть значок «Стрелка». И, наконец, меню «Список элементов» охватывается в подрядном списке.
Но … это недоступно. Если пользователь с нарушениями зрения с помощью вспомогательных технологий посещает эту страницу, он не подсказывает, что это выпадает или как взаимодействовать с ней. Кроме того, это полностью недоступно на клавиатуре.
Сделать пользовательский элемент доступным
Пользовательский элемент должен функционировать так же, как и семантические элементы в отношении навигации клавиатуры и доступности считывателя экрана.
Вот что нам нужно, чтобы сделать этот экран обработчиком доступным:
- У раскрывающейся метки должен быть удостоверение личности. Это потому, что мы будем использовать
Aria-Labelledby
накоторый будет функционировать как выброшенный выпуск, и этот атрибут принимает
id
HTML, который помечает его. Я дам ему идентификаторВыпадающаяся маршрута
Анкет -
Функционирование в виде выбора выпадения должно иметь
Роль = "Кнопка"
а такжеaria-labelledby = "раскрывающаяся марка"
Анкет -
Элемент нуждается в дополнительной информации, чтобы описать, что это такое. Таким образом, мы можем добавить
Как первый ребенок SVG.Открыть раскрытие - Контейнер выпадающего списка должен сообщить пользователю, расширено ли меню или нет. Мы можем добавить
aria-expeded = "false"
атрибут, чтобы сообщить эту информацию. Это должно быть обновлено с помощью JavaScript по мере изменения состояния.
Вот что нам нужно, чтобы сделать эту клавиатуру доступной:
-
который функционирует в виде выбора выпадения, нуждается в
tabindex = "0"
Таким образом, пользователь может сосредоточиться на элементе. - Все
В выпадающем меню также нужно
tabindex = "0"
Анкет
Вот доступный HTML:
- Label
- Option 1
-
- Option 1
- Option 2
Нам также необходимо добавить некоторую логику JavaScript, чтобы убедиться, что компонент функционирует так, как будет выпадает нативный выбор. Вот ожидаемое взаимодействие:
- Пользователь может сосредоточиться на элементе с помощью клавиатуры.
- Пользователь может открыть выберите «Выбравшись», нажав пробел или ввести клавиши.
- Пользователь может перемещаться по элементам элемента списка с клавишами стрелка вверх и вниз или клавиш вкладки.
- Пользователь может изменить выбор, сосредоточившись на элементе списка и нажав Enter.
- Пользователь может отклонить раскрытие, нажав.
- Как только пользователь выбирает элемент списка, список должен закрыться.
Итак, теперь давайте реализуем это.
Реализация доступности клавиатуры с помощью JavaScript
Во -первых, нам нужно взять ключевые коды для пробела, ввести клавишу, клавиши стрел вверх и вниз и клавишу Escape. (Я видел, как космическая панель представлена как 0 и 32, поэтому я установил ее на то, чтобы быть в безопасности).
const SPACEBAR_KEY_CODE = [0,32]; const ENTER_KEY_CODE = 13; const DOWN_ARROW_KEY_CODE = 40; const UP_ARROW_KEY_CODE = 38; const ESCAPE_KEY_CODE = 27;
Далее, есть несколько элементов, которые мы знаем, нам понадобятся. Я спасу их на постоянные. Мы также захотим отслеживать идентификаторы элементов списка, поэтому я объявлю пустой массив, который мы заполним.
const list = document.querySelector(".dropdown__list"); const listContainer = document.querySelector(".dropdown__list-container"); const dropdownArrow = document.querySelector(".dropdown__arrow"); const listItems = document.querySelectorAll(".dropdown__list-item"); const dropdownSelectedNode = document.querySelector("#dropdown__selected"); const listItemIds = [];
Далее нам нужно добавить некоторых слушателей событий в наши элементы, чтобы убедиться, что они будут реагировать на взаимодействие с пользователем. Не беспокойтесь о функциях, объявленных здесь, мы скоро доберемся до них.
dropdownSelectedNode.addEventListener("click", e => toggleListVisibility(e) ); dropdownSelectedNode.addEventListener("keydown", e => toggleListVisibility(e) ); // Add each list item's id to the listItems array listItems.forEach(item => listItemIds.push(item.id)); listItems.forEach(item => { item.addEventListener("click", e => { setSelectedListItem(e); closeList(); }); item.addEventListener("keydown", e => { switch (e.keyCode) { case ENTER_KEY_CODE: setSelectedListItem(e); closeList(); return; case DOWN_ARROW_KEY_CODE: focusNextListItem(DOWN_ARROW_KEY_CODE); return; case UP_ARROW_KEY_CODE: focusNextListItem(UP_ARROW_KEY_CODE); return; case ESCAPE_KEY_CODE: closeList(); return; default: return; } }); });
Теперь давайте создадим некоторые из этих функций, которые мы только что позвонили в слушателей событий. SetSelectedListItem
принимает событие и обновляет в данный момент выбранным элементом в поле «SELECT».
function setSelectedListItem(e) { let selectedTextToAppend = document.createTextNode(e.target.innerText); dropdownSelectedNode.innerHTML = null; dropdownSelectedNode.appendChild(selectedTextToAppend); }
Близкий
Закрывает список и обновляет ария-экспозиция
ценность.
function closeList() { list.classList.remove("open"); dropdownArrow.classList.remove("expanded"); listContainer.setAttribute("aria-expanded", false); }
Togglelistibility
принимает мероприятие. Если клавиша Escape была нажата, закройте список. В противном случае, если пользователь нажал или если он нажал на пробел или введите клавишу, переключите расширенное состояние и обновите ария-экспозиция
ценность соответственно. Наконец, если были нажаты клавиши со стрелками вниз или вверх, сосредоточьтесь на следующем элементе списка.
function toggleListVisibility(e) { let openDropDown = SPACEBAR_KEY_CODE.includes(e.keyCode) || e.keyCode === ENTER_KEY_CODE; if (e.keyCode === ESCAPE_KEY_CODE) { closeList(); } if (e.type === "click" || openDropDown) { list.classList.toggle("open"); dropdownArrow.classList.toggle("expanded"); listContainer.setAttribute( "aria-expanded", list.classList.contains("open") ); } if (e.keyCode === DOWN_ARROW_KEY_CODE) { focusNextListItem(DOWN_ARROW_KEY_CODE); } if (e.keyCode === UP_ARROW_KEY_CODE) { focusNextListItem(UP_ARROW_KEY_CODE); } }
FocusNextListitem
берет направление, которое либо констант Down_arrow_key_pressed
или Up_arrow_key_pressed
Анкет Если пользователь в настоящее время сосредоточен на «Select», сосредоточьтесь на первом элементе списка. В противном случае нам нужно найти индекс ориентированного в настоящее время элемента списка. Вот где ListItemsId
Массив пригодится. Теперь, когда мы знаем, где в списке целенаправленный элемент в настоящее время мы можем решить, что делать.
Если пользователь нажал клавишу со стрелками вниз, и он не на последнем элементе списка, сосредоточьтесь на следующем элементе списка. Если пользователь нажал клавишу стрелки вверх, и он не на первом элементе списка, сосредоточьтесь на предыдущем элементе списка.
function focusNextListItem(direction) { const activeElementId = document.activeElement.id; if (activeElementId === "dropdown__selected") { document.querySelector(`#${listItemIds[0]}`).focus(); } else { const currentActiveElementIndex = listItemIds.indexOf(activeElementId); if (direction === DOWN_ARROW_KEY_CODE) { const currentActiveElementIsNotLastItem = currentActiveElementIndex < listItemIds.length - 1; if (currentActiveElementIsNotLastItem) { const nextListItemId = listItemIds[currentActiveElementIndex + 1]; document.querySelector(`#${nextListItemId}`).focus(); } } else if (direction === UP_ARROW_KEY_CODE) { const currentActiveElementIsNotFirstItem = currentActiveElementIndex > 0; if (currentActiveElementIsNotFirstItem) { const nextListItemId = listItemIds[currentActiveElementIndex - 1]; document.querySelector(`#${nextListItemId}`).focus(); } } } }
Вот и все! Теперь у вас есть полностью совместимое раскрытие для клавиатуры! Я не буду покрывать здесь sass/css, но вы можете проверить это на Codepen Анкет
Оригинал: “https://dev.to/emmabostian/creating-a-custom-accessible-drop-down-3gmo”