Библиотека ally.js предназначена для повышения доступности веб-приложений, предоставляя инструменты для управления фокусом, клавиатурной навигацией и взаимодействием с элементами интерфейса. Один из ключевых аспектов доступности — корректная работа backdrop, то есть затемнённого или блокирующего слоя, который появляется при открытии модальных окон, диалогов или всплывающих панелей.
Для управления backdrop используется метод trapFocus. Он
позволяет задать область, в которой будет ограничен фокус пользователя.
Пример базовой инициализации:
import * as ally from 'ally.js';
const modal = document.getElementById('modal');
const backdrop = document.getElementById('backdrop');
function openModal() {
backdrop.style.display = 'block';
ally.trapFocus({
context: modal,
ignoreAccessiblyHidden: true,
});
}
Ключевые параметры trapFocus:
context — элемент, внутри которого фокус будет
ограничен.ignoreAccessiblyHidden — игнорировать элементы с
aria-hidden="true".defaultElement — элемент, который получает фокус по
умолчанию при активации trap.clickOutsideDeactivates — позволяет закрывать модальное
окно при клике вне него.Для корректного закрытия модального окна важно одновременно убрать фокусный ловец и скрыть фон:
function closeModal() {
backdrop.style.display = 'none';
if (trap) {
trap.deactivate();
}
}
Здесь trap — объект, возвращаемый функцией
ally.trapFocus. Его метод deactivate() снимает
ограничения на фокус и возвращает пользователю контроль над остальными
элементами страницы.
Для повышения удобства и доступности рекомендуется:
Пример:
modal.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
closeModal();
}
});
backdrop.addEventListener('click', () => {
closeModal();
});
ally.js позволяет организовывать stacking модальных окон, сохраняя порядок фокусировки:
const firstTrap = ally.trapFocus({ context: firstModal });
const secondTrap = ally.trapFocus({ context: secondModal });
secondTrap.activate(); // фокус ограничен вторым модальным
firstTrap.deactivate(); // предыдущий trap временно отключен
Важно при этом корректно возвращать активность предыдущему trap при закрытии верхнего модального окна.
inert.trapFocus:activate и
trapFocus:deactivate для кастомной логики (например,
анимаций или уведомлений скринридера).modal.addEventListener('trapFocus:activate', () => {
console.log('Фокус захвачен модальным окном');
});
modal.addEventListener('trapFocus:deactivate', () => {
console.log('Фокус возвращён к основной странице');
});
aria-hidden="true" для фонового контента
при активном backdrop.role="dialog" и
aria-modal="true" для модального окна.const modal = document.getElementById('modal');
const backdrop = document.getElementById('backdrop');
let trap;
function openModal() {
backdrop.style.display = 'block';
modal.setAttribute('aria-hidden', 'false');
trap = ally.trapFocus({
context: modal,
defaultElement: modal.querySelector('button, a, input'),
clickOutsideDeactivates: true
});
}
function closeModal() {
backdrop.style.display = 'none';
modal.setAttribute('aria-hidden', 'true');
if (trap) {
trap.deactivate();
}
}
Этот подход обеспечивает полную доступность, контроль фокуса и предотвращение случайного взаимодействия с контентом за backdrop, что делает интерфейс безопасным и удобным для всех пользователей.