Назад в Центр знаний
Платформа

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 сообщает подтверждённое состояние, а резервный путь должен сохранить тот же результат.

Содержание

Триггер открывает auto или manual popover в top layer; Escape или внешний клик закрывает его и возвращает фокус.

Выберите модель состояния

Спецификация 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 оставляет решение коду. Действие закрытия должно быть понятным.

#Popover API#Доступность#Фокус#Top Layer#Web Platform

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

Переведите BotBrowser из исследований в продакшн

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