Примечание: я все еще изучаю доступность, поэтому, если вы найдете недостаток в моем методе, пожалуйста, дайте мне знать в комментариях ниже!
Создать пользовательские компоненты сложно. Вы должны переопределить много стиля браузера по умолчанию, и часто это может быть утомительным. И в некоторых случаях невозможно стилизовать HTML -элементы. Это так с выбранным выпаданием.
Невозможно стилизовать выбранное выпадающее меню, потому что у нас нет возможности обернуть набор <Опция> Элементы в контейнере (который необходим для абсолютного позиционирования элементов списка против родительского элемента).
Таким образом, мы должны «взломать» наш путь к созданию выпадения. К сожалению, это обычно приводит к отсутствию доступности.
В этом уроке мы узнаем, как создать выбросы настраиваемого выбора, при этом соблюдая стандарты доступности W3C.
Вот выпадение, которое мы будем создавать:
Традиционно, при создании выбора выпадающего вниз, вы будете использовать следующее:
Проблема с использованием Элемент в том, что вы не можете обернуть ребенка <Опция> Элементы в контейнере. Зачем нам обернуть эти элементы в контейнер? Чтобы расположить выпадающий список под окном ввода.
В нашем случае мы хотим, чтобы элементы списка, <Опция> Элементы, которые будут расположены под коробка. Браузер отображает пункты меню по умолчанию в качестве наложения:
Чтобы относительно позиционировать дочерний элемент по отношению к родительскому элементу, так и в случае с пользовательским выпадающим меню, вы должны установить следующие свойства CSS:
.parent {
position: relative;
}
.child {
position: absolute;
top: 0;
left: 0;
}
Вы можете задаться вопросом: «Разве вы не можете переписать HTML на следующее (используя CSS выше)?
Ответ, к сожалению, Нет Анкет Вы не можете разместить Внутри Анкет
Поэтому мы должны создать доступный обходной путь.
Создание пользовательского выбора
Поскольку мы не можем использовать Элемент, я решил использовать серию и элементы.
Структура выглядит примерно так:
- Label
- Option 1
-
- Option 1
- Option 2
Это довольно просто.
- У нас есть весь компонент, завернутый в неупорядоченный список.
- Метка – это элемент списка.
- Выбор также является элементом списка.
- Затем у нас есть значок «Стрелка». И, наконец, меню «Список элементов» охватывается в подрядном списке.
Но … это недоступно. Если пользователь с нарушениями зрения с помощью вспомогательных технологий посещает эту страницу, он не подсказывает, что это выпадает или как взаимодействовать с ней. Кроме того, это полностью недоступно на клавиатуре.
Сделать пользовательский элемент доступным
Пользовательский элемент должен функционировать так же, как и семантические элементы в отношении навигации клавиатуры и доступности считывателя экрана.
Вот что нам нужно, чтобы сделать этот экран обработчиком доступным:
- У раскрывающейся метки должен быть удостоверение личности. Это потому, что мы будем использовать
Aria-Labelledbyнакоторый будет функционировать как выброшенный выпуск, и этот атрибут принимаетidHTML, который помечает его. Я дам ему идентификаторВыпадающаяся маршрутаАнкет -
Функционирование в виде выбора выпадения должно иметьРоль = "Кнопка"а также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”