Клавиатурная навигация

Библиотека ally.js предоставляет набор инструментов для управления фокусом и обеспечения доступности веб-интерфейсов с помощью клавиатуры. Основной принцип работы заключается в контроле фокуса элементов DOM и обеспечении корректного порядка навигации, что особенно важно для пользователей, использующих клавиатуру или вспомогательные технологии.

Клавиатурная навигация опирается на несколько ключевых понятий:

  • Фокусируемые элементы — элементы, которые могут получать фокус с клавиатуры (<a>, <button>, <input> и элементы с tabindex).
  • Порядок табуляции — последовательность перемещения фокуса при нажатии клавиши Tab.
  • Фокус-трап (focus trap) — замыкание фокуса внутри определенного контейнера.
  • Временные или скрытые элементы — элементы, доступные только при определенных условиях или скрытые визуально, но доступные для навигации с клавиатуры.

Определение фокусируемых элементов

Метод ally.query.focusable() позволяет получить список всех элементов, доступных для фокусировки. Он учитывает:

  • Стандартные фокусируемые теги (button, input, select, textarea, a[href]).
  • Элементы с атрибутом tabindex >= 0.
  • Скрытые или заблокированные элементы, если указаны специальные флаги.

Пример использования:

const focusableElements = ally.query.focusable({ context: document });
focusableElements.forEach(el => console.log(el));

Параметр context задает контейнер, в пределах которого ищутся элементы. Это позволяет ограничить поиск определенной секцией страницы.

Управление фокусом

Библиотека предоставляет методы для установки, получения и управления фокусом:

  • ally.focus() — переносит фокус на указанный элемент.
  • ally.has.focus() — проверяет, находится ли элемент в фокусе.
  • ally.next.focus() / ally.previous.focus() — позволяет программно перемещать фокус вперед или назад в порядке табуляции.

Пример установки фокуса на первый элемент формы:

const firstInput = document.querySelector('form input');
ally.focus(firstInput);

Для циклической навигации по модальному окну используется комбинация ally.next.focus() и контроля события keydown, чтобы реализовать фокус-трап.

Фокус-трап (Focus Trap)

Фокус-трап — это техника, которая ограничивает навигацию клавиатуры внутри определенного контейнера, например, модального окна. Это предотвращает уход фокуса за пределы интерактивной области до закрытия окна.

Реализация с ally.js:

const modal = document.getElementById('modal');

function trapFocus(event) {
  const focusableElements = ally.query.focusable({ context: modal });
  const firstEl = focusableElements[0];
  const lastEl = focusableElements[focusableElements.length - 1];

  if (event.key === 'Tab') {
    if (event.shiftKey) {
      if (document.activeElement === firstEl) {
        event.preventDefault();
        lastEl.focus();
      }
    } else {
      if (document.activeElement === lastEl) {
        event.preventDefault();
        firstEl.focus();
      }
    }
  }
}

modal.addEventListener('keydown', trapFocus);

Этот код обеспечивает циклическое перемещение фокуса внутри модального окна без выхода за его пределы.

Манипуляция атрибутом tabindex

ally.js позволяет динамически изменять доступность элементов:

  • ally.query.tabindex() — получение элементов с tabindex.
  • ally.query.tabindex({ context, includeOnlyTabbable: true }) — фильтрует только доступные для клавиатуры элементы.
  • Программное управление атрибутом tabindex позволяет временно исключать элементы из навигации или включать их при необходимости.

Пример временного отключения всех ссылок на странице:

const links = ally.query.tabindex({ context: document, includeOnlyTabbable: true });
links.forEach(link => link.setAttribute('tabindex', '-1'));

Управление видимостью и доступностью

Библиотека учитывает элементы, которые визуально скрыты, но остаются фокусируемыми. С помощью опций displayCheck можно контролировать, какие элементы считать доступными:

  • strict — только полностью видимые элементы.
  • non-zero-area — элементы с ненулевой областью отображения.
  • none — все элементы, включая скрытые.

Пример:

const visibleFocusable = ally.query.focusable({ context: document, displayCheck: 'strict' });

Интеграция с событиями клавиатуры

Для полноценной клавиатурной навигации необходимо сочетать ally.js с событиями keydown и keyup. Часто используется комбинация с обработкой клавиш Tab, Shift+Tab, Enter, Space и стрелок, чтобы реализовать пользовательские виджеты, списки, меню и аккордеоны, соответствующие стандартам WAI-ARIA.

document.addEventListener('keydown', event => {
  if (event.key === 'ArrowDown') {
    ally.next.focus();
    event.preventDefault();
  } else if (event.key === 'ArrowUp') {
    ally.previous.focus();
    event.preventDefault();
  }
});

Рекомендации по использованию

  • Разделять контейнеры с интерактивными элементами и управлять фокусом внутри каждого.
  • Использовать фокус-трап для модальных окон, всплывающих подсказок и кастомных диалогов.
  • Учитывать динамическое появление и удаление элементов, обновляя список фокусируемых элементов через ally.query.focusable().
  • Комбинировать управление tabindex и события клавиатуры для создания доступных интерфейсов с предсказуемым поведением.

Эти инструменты позволяют реализовать надежную и стандартизированную клавиатурную навигацию, соблюдая требования доступности и улучшая взаимодействие с веб-приложениями.