Popover API: фокус, закрытие и доступность
Определите доступный контракт для popover=auto и manual: top layer, Escape, внешний клик, фокус, события и резервный путь.
BotBrowser Team
Нужна структурированная документация по теме Платформа?
Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.
BotBrowser может повторить разрешённый fixture и записать видимые результаты открытия, закрытия и фокуса, но не гарантирует поведение ассистивных технологий и не превращает резервный путь в заявленную поддержку браузера. Для сценариев, где указатель сочетается с клавиатурой, добавьте проверки доступности Pointer Events и тестирование доступности автоматизации.
TL;DR
popover="auto"подходит для немодальной поверхности с light-dismiss;manualоставляет каждое закрытие приложению.- top layer сам по себе не создаёт ловушку фокуса, доступное имя или семантику диалога.
- Проверяйте
Escape, внешний клик, возврат фокуса и фонinertкак отдельные результаты. beforetoggleможет отменить переход;toggleсообщает подтверждённое состояние, а резервный путь должен сохранить тот же результат.
Содержание
- Выберите модель состояния
- Top layer и light-dismiss
- Фокус и inert: разные контракты
- Наблюдайте beforetoggle и toggle
- Сделайте полезный резервный путь
- Запустите ограниченную матрицу
- Итоги
Выберите модель состояния
Спецификация WHATWG HTML определяет атрибут popover и алгоритмы показа и скрытия. popover="auto" подходит для меню, подсказок и фильтров без модальности; браузер управляет стеком автоматических popover. popover="manual" передаёт решение приложению, когда несколько поверхностей должны оставаться открытыми или закрытие принадлежит кнопке «готово».
Не считайте атрибут синонимом <dialog>. Popover не становится модальным, не захватывает фокус и не получает доступное имя автоматически. Используйте настоящий button, popovertarget и имя, описывающее содержимое. Роль меню нужна только при реализации соответствующего поведения клавиатуры.
Руководство MDN Popover API описывает showPopover(), hidePopover() и togglePopover(). До императивного пути проверьте наличие API и явно сообщите пользователю содержимое, способ закрытия и доступную задачу позади поверхности.
Top layer и light-dismiss
Показанный popover попадает в top layer. Для auto браузер предоставляет light-dismiss, но это не гарантирует правильное положение при малом visual viewport, увеличении, виртуальной клавиатуре или iframe. Отдельно проверяйте Escape и внешний клик. Для manual нужен явный close button и обработчик; прозрачный слой не заменяет семантику.
Введение Chrome в Popover API объясняет цели top layer и light-dismiss, но не доказывает одинаковое поведение всех браузеров, встроенных представлений и ассистивных технологий. Запишите версию и viewport, проверяя видимый результат.
Фокус и inert: разные контракты
Показ не определяет место фокуса. Для подсказки, меню или редактора оставьте фокус на триггере либо перенесите его на первый полезный control. Сохраните opener и верните фокус подключённому enabled-элементу; если он исчез, используйте согласованный заголовок или следующую кнопку. Не вызывайте focus() для удалённого узла.
Проверьте, что клавиатура, указатель и ассистивная технология достигают нужных элементов управления. manual может намеренно оставить фон доступным; модальную задачу лучше выражает <dialog> с showModal(). Руководства WCAG по клавиатуре и focus-visible требуют проверять имя, роль, состояние, индикатор и следующую операцию.
Наблюдайте beforetoggle и toggle
beforetoggle срабатывает до перехода и может его отменить или подготовить решение о фокусе. toggle приходит после подтверждения. Быстрые переходы могут объединяться; записывайте ограниченную метку opened или closed-by-escape, а не текст страницы и не журнал каждого клика.
const trigger = document.querySelector('#filters-button');
const panel = document.querySelector('#filters-panel');
let opener = null;
trigger.addEventListener('click', () => {
opener = document.activeElement;
panel.togglePopover();
});
panel.addEventListener('beforetoggle', event => {
if (event.newState === 'open' && !trigger.isConnected) event.preventDefault();
});
panel.addEventListener('toggle', event => {
if (event.newState === 'closed' && opener?.isConnected) opener.focus();
});
Это шаблон координации, а не обещание одинакового порядка событий. После отмены поверхность и фокус должны оставаться рабочими; резервный путь должен выдавать эквивалентное состояние без API событий.
Сделайте полезный резервный путь
Проверьте API и используйте обычную кнопку, изначально скрытую область и кнопку закрытия с aria-controls. Сохраните контент и порядок фокуса. Для модальной задачи применяйте поддерживаемый паттерн dialog, а не выдавайте manual за modal. Обработайте отсутствующий метод, отказ фокуса, удалённый opener и изменение viewport. BotBrowser может сравнить заявленные видимые состояния в разрешённом контексте; он не сертифицирует речь screen reader и top layer каждого build.
Запустите ограниченную матрицу
| Путь | Ожидаемый результат | Что исследовать |
|---|---|---|
Вызов клавиатурой, auto | Открытие, видимый фокус, Escape закрывает | Фокус исчез |
Внешний клик, auto | Одно закрытие и возврат фокуса | Двойная очистка |
Close button, manual | Приложение скрывает и восстанавливает opener | Нет владельца закрытия |
| API отсутствует | Эквивалентный контент и клавиатура | Резервный путь недоступен |
| Узкий viewport | Выход видим, текст читаем | Единственный выход обрезан |
Повторите строки при увеличении, reduced motion, touch и узком viewport. Проверяйте document.activeElement, доступное имя, индикатор и следующую операцию. Fixture должен быть синтетическим, а журнал содержит только state labels.
Если popover должен следовать за движущимся trigger, используйте руководство по границам CSS anchor positioning, чтобы отдельно проверить anchor-name, резервные варианты и обрезку, не смешивая их с фокусом.
Итоги
Выберите auto или manual по владельцу закрытия, затем отдельно проверяйте top layer, light-dismiss, Escape, фокус, inert и резервный путь. WHATWG, MDN и Chrome описывают платформу; BotBrowser повторяет разрешённый видимый fixture, а семантика и доступное восстановление остаются обязанностью приложения.
Источники
FAQ
popover="auto" - это модальный диалог?
Нет. Для модальной задачи используйте <dialog> и showModal().
Top layer перемещает фокус автоматически?
Нет. Определите назначение, возврат и резервный путь при исчезновении opener.
Каждый popover должен закрываться внешним кликом?
Нет. auto предусматривает light-dismiss, а manual оставляет решение коду. Действие закрытия должно быть понятным.
Эта статья входит в руководство: Поверхности веб-платформы: карта проверки
Похожие статьи
События указателя и доступный ввод: мышь, сенсорный экран и перо
Начало работыТестирование доступности браузерной автоматизации
ПлатформаCSS Anchor Positioning: границы layout и overlay
ПлатформаГолоса синтеза речи и доступное воспроизведение в браузере
ПлатформаWeb Share API: границы разрешений и безопасные запасные варианты
ПлатформаNavigation API, история и границы приватности
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.