Прогрессивное улучшение

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

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


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

Фокусировка на элементах

Основная функция ally.js — это управление фокусом. Методы tabNext, tabPrevious и focusable позволяют определить и установить фокус на интерактивные элементы:

const nextElement = ally.query.next({
  context: document.body,
  startElement: document.activeElement
});
if(nextElement) nextElement.focus();
  • context — область поиска доступных элементов.
  • startElement — текущий активный элемент для расчета следующего фокуса.
  • focusable — возвращает массив элементов, на которые можно переместить фокус, исключая скрытые и недоступные.

Фокусировка внутри модальных окон

Для модальных окон ally.js предоставляет метод trapFocus, который ограничивает навигацию только элементами внутри контейнера:

const modal = document.getElementById('modal');
const stopFocusTrap = ally.trapFocus({
  context: modal
});
  • trapFocus автоматически отслеживает клавиши Tab и Shift+Tab.
  • Возврат функции stopFocusTrap позволяет деактивировать ограничение после закрытия модального окна.

Доступность интерактивных элементов

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

Метод tabbable() возвращает список всех элементов, на которые можно перейти с помощью клавиши Tab:

const tabbableElements = ally.query.tabbable({ context: modal });
  • Игнорируются элементы с display: none, visibility: hidden или disabled.
  • Поддерживаются динамически добавленные элементы, что важно для SPA и компонентов, создаваемых на лету.

Проверка доступности

Функция is.focusable(element) проверяет, можно ли установить фокус на конкретный элемент:

if(ally.is.focusable(button)) {
  button.focus();
}

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


Работа с ARIA и вспомогательными технологиями

Ally.js автоматически учитывает ARIA-атрибуты, такие как:

  • aria-hidden — элементы с этим атрибутом игнорируются при навигации.
  • aria-disabled — предотвращает фокусировку на элементах, которые визуально доступны, но недоступны для взаимодействия.
  • role="dialog" и другие роли модальных компонентов — помогают правильно ограничивать фокус.

Применение этих атрибутов совместно с ally.js обеспечивает соответствие WCAG 2.1 и улучшает поддержку экранных читалок.


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

Временное скрытие элементов

Метод ignore позволяет временно исключить элементы из навигации по клавиатуре:

const stopIgnoring = ally.maintain.hidden({
  context: document.body,
  filter: '.sidebar'
});
  • Используется для скрытия элементов, которые не должны быть доступны пользователю в данный момент.
  • Возврат функции stopIgnoring восстанавливает стандартное поведение.

Фокус на первый или последний элемент

ally.query.first({ context: modal }).focus();
ally.query.last({ context: modal }).focus();

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


Интеграция с динамическим контентом

Ally.js поддерживает динамически изменяемые интерфейсы, такие как одностраничные приложения (SPA) и интерактивные компоненты. Методы tabbable и focusable автоматически обновляют список элементов при изменении DOM, что исключает необходимость ручного пересчета.

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

const listContainer = document.querySelector('.dynamic-list');
const updateFocusable = () => {
  const items = ally.query.tabbable({ context: listContainer });
  items.forEach(item => item.setAttribute('tabindex', '0'));
};

listContainer.addEventListener('DOMNodeInserted', updateFocusable);

Расширение функционала через плагины и кастомизацию

Ally.js предоставляет интерфейс для кастомных фильтров элементов, позволяя расширять стандартное поведение. Можно определить собственные правила, исключающие или включающие элементы в фокусную навигацию:

const customFocusable = ally.query.focusable({
  context: document.body,
  filter: element => element.dataset.customFocusable === 'true'
});
  • filter — функция, возвращающая true для включения элемента в список фокусируемых.
  • Позволяет интегрировать ally.js в нестандартные компоненты UI.

Практические рекомендации

  • Использовать trapFocus для модальных окон, всплывающих подсказок и диалогов.
  • Всегда проверять элементы через is.focusable перед программной фокусировкой.
  • Для динамических интерфейсов применять tabbable и focusable, чтобы поддерживать актуальность списка интерактивных элементов.
  • Комбинировать ally.js с ARIA-атрибутами для обеспечения максимальной совместимости с экранными читалками.
  • Встроенные методы ally.js позволяют реализовать полностью клавиатурно-доступные интерфейсы, соответствующие современным стандартам доступности.