Возврат фокуса после закрытия

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


Основные принципы возврата фокуса

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

    const triggerElement = document.querySelector('#openModalButton');
    let lastFocusedElement;
    
    triggerElement.addEventListener('click', () => {
        lastFocusedElement = document.activeElement;
        openModal();
    });
  2. Установка фокуса на первый интерактивный элемент внутри модального окна После открытия модального блока важно переместить фокус внутрь него. ally.js предоставляет метод tabbable() для поиска всех элементов, доступных для табуляции, и функцию focus() для установки фокуса.

    import { tabbable } from 'ally.js';
    
    function openModal() {
        const modal = document.querySelector('#modal');
        modal.style.display = 'block';
        const focusableElements = tabbable(modal);
        if (focusableElements.length) {
            focusableElements[0].focus();
        }
    }
  3. Возврат фокуса после закрытия Для восстановления фокуса используется сохранённая ранее ссылка на исходный элемент. Это обеспечивает непрерывность навигации и соответствие стандартам доступности WCAG.

    function closeModal() {
        const modal = document.querySelector('#modal');
        modal.style.display = 'none';
        if (lastFocusedElement) {
            lastFocusedElement.focus();
        }
    }
    
    const closeButton = document.querySelector('#closeModalButton');
    closeButton.addEventListener('click', closeModal);

Контроль фокуса с ally.js

Ally.js не ограничивается простым возвратом фокуса. Он позволяет более гибко управлять интерактивными зонами:

  • trapFocus() — функция, блокирующая фокус внутри выбранного контейнера. Используется для модальных окон, чтобы табуляция не выходила за пределы активного блока.

    import { trapFocus } from 'ally.js';
    
    const modal = document.querySelector('#modal');
    trapFocus({
        context: modal,
        escapeDeactivates: true
    });
  • focus() — метод, безопасно устанавливающий фокус на элемент, проверяя его доступность.

    import { focus } from 'ally.js';
    
    focus(focusableElements[0]);
  • tabbable() — возвращает список всех элементов внутри контейнера, на которые можно переместить фокус с помощью клавиши Tab. Это удобно для поиска первого или последнего интерактивного элемента при управлении циклом фокуса.


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

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

  2. Фокусировать первый интерактивный элемент После открытия модального блока всегда перемещать фокус на первый tabbable элемент, чтобы пользователи клавиатуры сразу попадали в управляемую область.

  3. Использовать безопасный возврат Перед установкой фокуса на исходный элемент проверять его наличие и доступность, чтобы избежать ошибок при динамическом изменении DOM.

  4. Тестировать сценарии с клавиатурой и экранными читалками Фокус должен оставаться логичным при переходе между элементами интерфейса, независимо от того, используется ли Tab, Shift+Tab или Escape для закрытия модального окна.


Обработка динамически созданных элементов

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

function createAndOpenModal() {
    const modal = document.createElement('div');
    modal.id = 'modal';
    modal.innerHTML = '<button id="firstButton">OK</button>';
    document.body.appendChild(modal);
    
    const focusableElements = tabbable(modal);
    if (focusableElements.length) {
        focus(focusableElements[0]);
    }
}

Управление закрытием через клавиатуру

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

document.addEventListener('keydown', (event) => {
    if (event.key === 'Escape') {
        closeModal();
    }
});

Это решение совместимо с методами ally.js, обеспечивая корректный и безопасный возврат фокуса, без выхода за пределы активной области.


Итоговые механизмы

  • Запоминание предыдущего фокуса перед открытием.
  • Перемещение фокуса на первый tabbable элемент внутри модального блока.
  • Ограничение фокуса внутри контейнера с trapFocus.
  • Возврат фокуса на исходный элемент после закрытия.
  • Обработка динамически создаваемых элементов и клавиатурных сценариев.

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