Enter The Dragon (Drop): переупорядочивание списка доступных
Опубликовано: 2022-03-10За годы работы веб-разработчиком, уделяющим особое внимание доступности, я в основном имел дело с широко распространенными стандартизированными компонентами пользовательского интерфейса, хорошо поддерживаемыми вспомогательными технологиями (AT). Для этих типов виджетов существуют краткие методы разработки ARIA, а также отличные инструменты, такие как axe-core, которые можно использовать для тестирования веб-компонентов на наличие проблем с доступностью. Создание менее распространенных виджетов, особенно тех, которые не имеют общепринятых соглашений для взаимодействия с пользователем, может быть очень сложной задачей.
Одна из самых сложных проблем, с которыми я сталкивался, — это переупорядочиваемый список перетаскивания. Хотя переупорядочиваемый список является довольно часто используемым виджетом с интуитивно понятными соглашениями для пользователей мыши, неясно, как пользователи вспомогательных технологий, использующих только клавиатуру, могут выполнять эту простую задачу. Из-за отсутствия поддерживаемых атрибутов ARIA Dragon Drop использует живые регионы для передачи информации, необходимой всем пользователям для изменения порядка списка.
Живые регионы
Активные области — это элементы HTML, оснащенные атрибутами ARIA, которые можно использовать для уведомления программ чтения с экрана об изменениях содержимого. Они позволяют нам предоставлять полностью настраиваемое объявление для чтения с экрана без необходимости перемещать фокус! Активные области отлично подходят для обновлений в реальном времени в удаленных частях страницы, обновлений статуса и информации, зависящей от времени.
Они обычно используются в журналах чата, индикаторах прогресса, обновлениях спортивных результатов и оповещениях о погоде, но их следует использовать с осторожностью, поскольку они могут легко создать слишком многословный интерфейс для пользователей программ чтения с экрана. Если вы новичок в живых регионах или просто хотите узнать, на что они способны, загляните на мою игровую площадку живых регионов, которая позволяет вам настроить свой собственный живой регион.
Если вы хотите использовать живые регионы в своем приложении, обратитесь к модулю Live Region в npm.
<div aria-live="assertive" role="log" aria-relevant="additions" aria-atomic="true"></div>
Зачем использовать живые регионы?
В идеальном мире я мог бы просто положиться на атрибуты ARIA перетаскивания aria-grabbed
и aria-dropeffect
. Однако на самом деле поддержка этих атрибутов встречается редко, а там, где они поддерживаются, это сбивает с толку и противоречит здравому смыслу пользователей программ чтения с экрана. Вдобавок ко всему, эти два атрибута устарели, начиная с ARIA 1.1, а это означает, что мы не увидим роста поддержки этих атрибутов в будущем.
Разговор W3C об этом устаревании можно найти здесь. Из-за этих проблем я решил не использовать эффекты захвата aria-grabbed
и aria-dropeffect
в Dragon Drop. Различная поддержка атрибутов ARIA в широком спектре пар вспомогательных технологий и браузеров весьма распространена в мире специальных возможностей. К счастью, такие атрибуты активного региона, как role
, aria-live
, aria-relevant
и aria-atomic
довольно широко поддерживаются программами чтения с экрана, такими как JAWS, NVDA и VoiceOver.
Оптимизированная доступность
Dragon Drop — это модуль переупорядочивания списков с широкими возможностями настройки, который работает для пользователей с мышью, клавиатурой и вспомогательными технологиями. Пару лет назад, когда я решил написать его, доступные списки переупорядочения появлялись несколько раз в проектах, над которыми я работал, но я еще не видел работающего решения. Из десятков плагинов перетаскивания списков, с которыми я сталкивался, большинство из них не были разработаны с учетом доступности и, как следствие, были очень недоступны.
Dragon Drop был протестирован с VoiceOver, JAWS и NVDA и позволяет пользователям AT успешно изменять порядок списка.
Я намеревался ответить на все вопросы, которые могут возникнуть у любого пользователя при столкновении с переупорядочиваемым списком. Ответы на эти вопросы для зрячих пользователей мышей были даны с помощью общепринятых соглашений, но как насчет остальных пользователей?
Как я могу забрать предмет?
Предоставляя элемент управления, который передает состояние захвата элемента вместе с текстом справки верхнего уровня, мы можем ответить на этот вопрос. Например, элемент управления с доступным текстом (собранным AT, несмотря на его имя, роль и значение) «Переупорядочить элемент 1, кнопка-переключатель» сообщает пользователю, что это кнопка, которая при активации поднимает элемент и запускает изменение порядка.
Dragon Drop использует атрибут aria-pressed
, чтобы пользователи AT знали, когда элемент «перетаскивается», а когда нет. Его можно настроить так, чтобы можно было перетаскивать весь элемент или только дочернюю «дескриптор перетаскивания», что в любом случае гарантирует наличие role="button"
и tabindex="0"
.
Когда элемент перетаскивания активируется, к элементу применяется aria-pressed="true"
и настраиваемое объявление, например "Элемент 1 захвачен" , читается программам чтения с экрана через живую область.
Как я могу переместить предмет?
Использование aria-describedby
для связывания элементов управления с полезным текстом справки, таким как «Активируйте кнопку изменения порядка и используйте клавиши со стрелками, чтобы изменить порядок списка, или используйте мышь для перетаскивания/изменения порядка». сообщает пользователю, как на самом деле изменить порядок. Это позволяет пользователям программ чтения с экрана знать, что при нажатии элемента клавиши со стрелками вверх и вниз будут перемещать элемент вверх и вниз по списку соответственно.
Как я могу выбросить предмет?
Поскольку используется атрибут aria-pressed
, пользователи могут легко сказать, как удалить элемент. Так или иначе, форма или форма, все наиболее широко используемые средства чтения с экрана передают нажатое состояние кнопки-переключателя. Атрибут aria-pressed устанавливается в значение «false», когда элемент отбрасывается, и программам чтения с экрана зачитывается индивидуальное объявление, например «Элемент 1 удален» .
Как я узнаю, что список был изменен?
Каждый раз, когда клавиши со стрелками вверх и вниз используются для изменения порядка в списке, мы должны убедиться, что все пользователи уведомлены об этом изменении. Для незрячих пользователей мы снова должны полагаться на живые регионы. Настраиваемое объявление, такое как «Список был изменен, элемент 1 теперь 4-й в списке». , считывается для передачи обновленного состояния переупорядоченного списка. Это важно, потому что у зрячих пользователей есть немедленная визуальная обратная связь об измененном порядке, и та же самая информация должна быть передана пользователям AT.
Как отменить повторный заказ?
Поскольку мы не можем полагаться на общепринятое соглашение для такого взаимодействия, мы можем просто включить в текст справки такие указания, как «Нажмите escape, чтобы отменить изменение порядка» . Кроме того, мы используем активную область для предоставления настраиваемых показаний, которые уведомляют пользователя об отмене.
Взаимодействие с клавиатурой
Ключ | Поведение |
---|---|
Ввод или пробел | Переключает элемент между состояниями «захвачен» и «выброшен». |
"↓" | Перемещает «захваченный» элемент вниз в списке |
"↑" | Перемещает «захваченный» элемент вверх в списке |
Esc | Отменяет изменение порядка и восстанавливает первоначальный порядок |
Увидеть дракона в действии
Посмотрите демонстрацию Dragon Drop, в которой вы испытаете несколько разных конфигураций.
Добавление Dragon Drop в ваше приложение
Dragon Drop преобразует ваш обычный список в полностью доступный переупорядочиваемый список с помощью перетаскивания:
<ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> <script> const dragon = document.getElementById('dragon'); // Enter the dragon new DragonDrop(dragon); </script>
Установка
Dragon Drop — это проект с открытым исходным кодом (лицензия MIT), который можно установить через npm:
$ npm install drag-on-drop
Его можно использовать с такими модулями, как browserify или webpack:
// if you're not down with ES6, you can require('drag-on-drop') import DragonDrop from 'drag-on-drop';
Dragon Drop также можно легко добавить на вашу страницу с помощью CDN unpkg:
<script source="https://unpkg.com/drag-on-drop"></script> <script> var dragonDrop = new DragonDrop(listElement); </script>
Конфигурация
Для поддержки широкого спектра вариантов использования Dragon Drop очень настраивается.
Ниже приведена конфигурация по умолчанию:
{ item: 'li', handle: 'button', activeClass: 'dragon-active', inactiveClass: 'dragon-inactive', announcement: { grabbed: el => `Item ${el.innerText} grabbed`, dropped: el => `Item ${el.innerText} dropped`, reorder: (el, items) => { const pos = items.indexOf(el) + 1; const text = el.innerText; return `The list has been reordered, ${text} is now item ${pos} of ${items.length}`; }, cancel: 'Reordering cancelled' } }
Объявления
Параметр конфигурации «объявление» Dragon Drop является наиболее важным, поскольку он является основой программы чтения с экрана, которую предоставляет Dragon Drop. Это объект, содержащий функции "grabbed"
, "dropped"
, "reorder"
и "cancel"
, позволяющие создавать настраиваемые объявления в реальном времени для всех происходящих взаимодействий.
Каждая из этих функций должна возвращать строку текста объявления, которая добавляется к активной области, когда происходит данное действие. Дополнительным преимуществом использования этих функций является то, что они поддерживают локализацию сообщений активного региона.
Чтобы облегчить объявления, элемент элемента списка, в котором произошло действие, и массив элементов в списке передаются в качестве аргументов соответственно.
{ announcement: { // grabbed is called when an item is picked up grabbed: (targetItem, items) => `${targetItem.innerText} grabbed`, // dropped is called when an item is dropped dropped: (targetItem, items) => `${targetItem.innerText} grabbed`, // reorder is called each time the order of the list is altered reorder: (targetItem, items) => { return `${targetItem.innerText} is now ${items.indexOf(targetItem) + 1} of ${items.length}` }, // cancel is called when a reordering is cancelled (via escape key) cancel: () => 'The initial order has been restored, reordering cancelled' } }
Текст справки
Крайне важно, чтобы вы предоставили текст справки, описывающий, как использовать переупорядочиваемый список. Это то, чего Dragon Drop не делает для вас, чтобы оставаться менее самоуверенным в том, как этот текст становится доступным для вспомогательных технологий. Рекомендуемая реализация — использовать aria-describedby
, чтобы связать текст справки с интерактивными элементами, например так:
<p>Activate the reorder button and use the arrow keys to reorder the list or use your mouse to drag/reorder. Press escape to cancel the reordering.</p> <ul> <li> <button>Reorder Item 1</button> <span>Item 1</span> </li> <li> <button>Reorder Item 2</button> <span>Item 2</span> </li> <li> <button>Reorder Item 3</button> <span>Item 3</span> </li> </ul>
Падение дракона на GitHub
Недавно вышла третья версия Dragon Drop. Если вы заинтересованы в его использовании, обратитесь к документации Dragon Drop на GitHub. Особая благодарность создателям Dragula, модуля, который Dragon Drop использует для взаимодействия с мышью, а также Аарону Перлману, который разработал потрясающий логотип!
Будущее Дракона
Если в будущем в техническую спецификацию WAI-ARIA будет добавлено взаимодействие с перетаскиванием, тот факт, что Dragon Drop полагается на нестандартное взаимодействие и живые регионы, может измениться. Я продолжу проводить тесты, гарантируя, что он будет хорошо поддерживаться как можно большим количеством программ чтения с экрана, и буду в курсе последних спецификаций ARIA. Кроме того, в разработке находится довольно много функций, включая поддержку сенсорных экранов/мобильных устройств, а также многоколоночные списки (например, доски спринтов). Еще одна функция, которая может быть добавлена в будущем, — это компонент Dragon Drop React.
В настоящее время Dragon Drop можно использовать с React, как показано в демонстрации ниже, но это не идеально, поскольку изменения DOM, вызванные переупорядочением списка, не улавливаются React, что может привести к неожиданному поведению. Я призываю всех, кто находит ошибки в Dragon Drop или даже имеет идеи для новых функций, создать проблему на GitHub. Все отзывы и вклад приветствуются и высоко ценятся!