ESC и клик вне диалога

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


Обработка клавиши ESC

Клавиша Escape часто используется для закрытия модальных окон или отмены текущих действий. ally.js предоставляет удобные методы для отслеживания событий клавиатуры и управления фокусом после закрытия диалога.

Пример: закрытие модального окна по ESC

import * as ally from 'ally.js';

const modal = document.querySelector('#modal');

function closeModal() {
    modal.style.display = 'none';
    ally.query.firstTabbable({context: document.body})?.focus();
}

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

Ключевые моменты:

  • Использование ally.query.firstTabbable() позволяет вернуть фокус на первый доступный интерактивный элемент после закрытия модального окна.
  • Проверка event.key === 'Escape' гарантирует корректную обработку клавиши во всех современных браузерах.
  • Важно останавливать дальнейшее распространение события, если диалог закрыт, чтобы избежать конфликтов с другими обработчиками.

Детекция клика вне диалога

Для закрытия диалога при клике вне его области используется определение контекста через ally.js. Это позволяет точно выявлять элементы, которые находятся «за пределами» модального окна.

Пример: клик вне диалога

function handleOutsideClick(event) {
    if (!modal.contains(event.target)) {
        closeModal();
    }
}

document.addEventListener('click', handleOutsideClick);

Особенности реализации:

  • Метод Element.contains() обеспечивает проверку вложенности, определяя, находится ли целевой элемент внутри диалога.
  • Событие click отслеживается на уровне document, что позволяет улавливать клики на любом участке страницы.
  • Для предотвращения закрытия при клике внутри диалога можно использовать event.stopPropagation() на внутренних элементах.

Фокус-трейп в модальных окнах

Для соблюдения принципов доступности необходимо ограничивать фокус клавиатуры элементами диалога. ally.js предоставляет утилиты для реализации focus trap:

import * as ally from 'ally.js';

const focusTrap = ally.tab.trap({
    context: modal,
    trapFocus: true,
    onDeactivate: () => {
        ally.query.firstTabbable({context: document.body})?.focus();
    }
});

focusTrap.activate();

Объяснение работы:

  • ally.tab.trap() создаёт область, в пределах которой фокус клавиатуры циклически перемещается между интерактивными элементами.
  • Опция trapFocus: true блокирует выход фокуса за пределы диалога при нажатии Tab или Shift+Tab.
  • Обработчик onDeactivate возвращает фокус на элемент, с которого пользователь начал взаимодействие.

Совмещение ESC и клика вне диалога

Для комплексного управления модальными окнами события keydown и click объединяются с focus trap:

function openModal() {
    modal.style.display = 'block';
    focusTrap.activate();
}

function closeModal() {
    modal.style.display = 'none';
    focusTrap.deactivate();
}

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

document.addEventListener('click', (event) => {
    if (!modal.contains(event.target)) {
        closeModal();
    }
});

Рекомендации:

  • Активация focus trap происходит при открытии модального окна, деактивация — при закрытии.
  • ESC и клик вне диалога работают синхронно, не нарушая управление фокусом.
  • Использование ally.js упрощает обеспечение доступности для пользователей с клавиатурой и вспомогательными технологиями.

Поддержка сложных сценариев

Библиотека позволяет реализовать несколько уровней модальных окон и динамические диалоги. Для этого:

  1. Создаются отдельные focus trap для каждого диалога.
  2. В событиях ESC и клика проверяется активный диалог.
  3. После закрытия текущего диалога фокус возвращается на последний активный элемент предыдущего уровня.

Оптимизация и производительность

  • Избегать добавления множества глобальных обработчиков click и keydown; лучше использовать делегирование.
  • Использовать ally.query.tabbable({context: modal}) для динамического обновления списка элементов при изменении содержимого.
  • При множественных диалогах хранить стек активных модальных окон для корректного управления focus trap.

Вывод

Использование ally.js для управления ESC и кликом вне диалога обеспечивает:

  • Полноценный focus management.
  • Соответствие стандартам доступности (WCAG 2.1).
  • Универсальную работу с клавиатурой и мышью без конфликтов с другими элементами страницы.

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