Фокус и его управление

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

Фокус в DOM связан с двумя состояниями: активный элемент (document.activeElement) и элемент, который может быть фокусирован. Не каждый элемент может быть естественно фокусируемым; для этого необходимо использовать атрибуты tabindex или стандартные элементы формы (<button>, <input>, <a> с href).

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

ally.js предоставляет функции для определения, может ли элемент быть фокусируемым:

import * as ally from 'ally.js';

const button = document.querySelector('button');

const isFocusable = ally.is.focusable(button);
const isTabbable = ally.is.tabbable(button);
  • is.focusable проверяет, можно ли установить фокус на элемент вообще.
  • is.tabbable проверяет, будет ли элемент доступен при навигации с помощью клавиши Tab.

Эти функции учитывают стили CSS (display: none, visibility: hidden), атрибут disabled и другие ограничения, что позволяет точно определить доступность элемента.

Навигация по фокусу

Для управления последовательностью фокуса ally.js предлагает методы поиска элементов, по которым можно перемещаться клавишей Tab:

const tabbableElements = ally.query.tabbable({
  context: document,
});
  • query.tabbable возвращает массив элементов, доступных при последовательной навигации по Tab.
  • query.focusable возвращает все элементы, на которые возможно установить фокус, включая те, что не доступны через Tab.

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

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

ally.js позволяет устанавливать фокус на любой элемент программно с учётом доступности:

ally.focus.within(button);
ally.focus.firstTabbable(document.querySelector('#modal'));
ally.focus.lastTabbable(document.querySelector('#modal'));
  • focus.within устанавливает фокус внутри указанного контейнера.
  • focus.firstTabbable и focus.lastTabbable позволяют управлять фокусом в пределах компонента, обеспечивая циклическую навигацию.

Такое управление необходимо для соблюдения принципов доступности при работе с модальными окнами и диалогами.

Обработка событий фокуса

ally.js упрощает слежение за изменениями фокуса:

ally.on.focus(event => {
  console.log('Фокус изменился', event.target);
});
  • Поддерживаются глобальные наблюдатели, отслеживающие любые изменения фокуса.
  • Можно фильтровать события по определённым контейнерам или типам элементов.

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

Работа с управляемым фокусом (Focus Trap)

Для сложных интерфейсов важно изолировать фокус внутри определённого контейнера, чтобы пользователи не уходили за пределы модального окна:

const modal = document.querySelector('#modal');
const focusTrap = ally.trap.focus(modal, {
  escapeDeactivates: true,
  allowOutsideClick: false,
});
  • trap.focus блокирует фокус внутри контейнера, перенаправляя навигацию Tab циклически.
  • Опции позволяют управлять поведением клавиши Escape и кликов вне контейнера.

Focus trap обеспечивает корректное поведение интерфейса и предотвращает потерю фокуса при взаимодействии с модальными компонентами.

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

При динамическом добавлении элементов на страницу необходимо обновлять список фокусируемых элементов:

const newButton = document.createElement('button');
document.body.appendChild(newButton);

if (ally.is.tabbable(newButton)) {
  ally.focus.within(newButton);
}

ally.js учитывает изменения DOM и позволяет корректно обрабатывать новые элементы без дополнительной ручной логики.

Стилизация элементов с фокусом

Хотя ally.js не занимается CSS напрямую, библиотека может быть использована вместе с классами для визуального отображения состояния фокуса:

:focus-visible {
  outline: 2px solid #0078d7;
  outline-offset: 2px;
}
  • Использование :focus-visible обеспечивает видимую индикацию фокуса только для навигации с клавиатуры, сохраняя чистоту интерфейса при работе мышью.
  • ally.js позволяет программно фокусировать элементы, и CSS автоматически применяет указанные стили.

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

  1. Всегда проверять, что все интерактивные элементы фокусируемы.
  2. Использовать focus trap для модальных и всплывающих компонентов.
  3. Проверять tabbable элементы для корректной последовательности навигации.
  4. Использовать события фокуса для динамического интерфейса и подсветки активного элемента.
  5. Не полагаться только на CSS, комбинировать с ally.js для контроля логики фокуса.

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