Использование API всплывающих окон
API всплывающих окон предоставляет разработчикам стандартный, согласованный и гибкий механизм для отображения содержимого всплывающих окон поверх другого контента страницы. Содержимое всплывающего окна может управляться декларативно с помощью атрибутов HTML или через JavaScript. Эта статья предоставляет подробное руководство по использованию всех его функций.
Создание декларативных всплывающих окон
В самом простом виде всплывающее окно создается путем добавления атрибута popover к элементу, который должен содержать содержимое всплывающего окна. Также необходим id для ассоциации всплывающего окна с его элементами управления.
<div id="mypopover" popover>Popover content</div>
Примечание: Установка атрибута popover без значения эквивалентна установке popover="auto".
Добавление этого атрибута скрывает элемент при загрузке страницы, установив display: none на нем. Для отображения/скрытия всплывающего окна необходимо добавить элементы управления. Вы можете установить <button> (или <input> типа type="button") в качестве кнопки управления всплывающим окном, присвоив ему атрибут popovertarget, значение которого должно быть идентификатором всплывающего окна для управления:
<button popovertarget="mypopover">Toggle the popover</button> <div id="mypopover" popover>Popover content</div>
По умолчанию кнопка действует как переключатель — многократное нажатие на нее переключает всплывающее окно между отображением и скрытием.
Если вы хотите изменить это поведение, используйте атрибут popovertargetaction — он принимает значение "hide", "show", или "toggle". Например, для создания отдельных кнопок показа и скрытия можно сделать так:
<button popovertarget="mypopover" popovertargetaction="show"> Show popover </button> <button popovertarget="mypopover" popovertargetaction="hide"> Hide popover </button> <div id="mypopover" popover>Popover content</div>
Вы можете увидеть, как предыдущий фрагмент кода отображается в нашем примере базового декларативного всплывающего окна (исходный код).
Примечание: Если атрибут popovertargetaction опущен, "toggle" является значением по умолчанию для действия, которое будет выполнено кнопкой управления.
Когда всплывающее окно отображается, у него удаляется атрибут display: none и оно помещается в верхний слой, чтобы оно находилось поверх всего остального содержимого страницы.
Автоматическое состояние и «лёгкое закрытие»
Когда элемент всплывающего окна задан с атрибутами popover или popover="auto", как показано выше, он имеет автоматическое состояние. Два важных поведения, которые следует отметить, касаются автоматического состояния:
- Всплывающее окно может быть «легко закрыто» — это означает, что вы можете скрыть всплывающее окно, кликнув вне его.
- Всплывающее окно также можно закрыть с помощью механизмов, специфичных для браузера, таких как нажатие клавиши Esc.
- Обычно только одно всплывающее окно может быть отображено в одно время — отображение второго всплывающего окна, когда уже отображено одно, приведет к скрытию первого. Исключением из этого правила являются вложенные авто-всплывающие окна. Подробности см. в разделе Вложенные всплывающие окна.
Примечание: Всплывающие окна с автоматическим состоянием также закрываются при успешном вызове HTMLDialogElement.showModal() и Element.requestFullscreen() на других элементах документа. Однако имейте в виду, что вызов этих методов на уже отображаемом всплывающем окне приведет к ошибке, потому что такое поведение не имеет смысла для уже отображенного всплывающего окна. Тем не менее, вы можете вызвать их на элементе с атрибутом popover , который в данный момент не отображается.
Автоматическое состояние полезно, когда вы хотите отображать только одно всплывающее окно за раз. Возможно, у вас есть несколько сообщений UI, которые вы хотите отобразить, но не хотите, чтобы отображение стало перегруженным и запутанным, или, возможно, вы отображаете сообщения состояния, где новое состояние заменяет любое предыдущее состояние.
Вы можете наблюдать описанное выше поведение в действии в нашем примере нескольких автоматических всплывающих окон (исходный код). Попробуйте закрыть всплывающие окна лёгким кликом, а затем посмотреть, что произойдёт, когда вы попытаетесь отобразить оба одновременно.
Использование ручного состояния всплывающего окна
Альтернативой автоматическому состоянию является ручное состояние, достигаемое установкой popover="manual" на элементе всплывающей подсказки:
<div id="mypopover" popover="manual">Popover content</div>
В этом состоянии:
- Всплывающая подсказка не может быть закрыта «лёгким» способом, хотя декларативные кнопки показа/скрытия/переключения (как показано ранее) по-прежнему будут работать.
- Несколько независимых всплывающих подсказок могут быть показаны одновременно.
Вы можете увидеть это поведение в действии в нашем примере нескольких ручных всплывающих подсказок (исходный код).
Отображение всплывающих подсказок с помощью JavaScript
Вы также можете управлять всплывающими подсказками с помощью JavaScript API.
Свойство HTMLElement.popover может быть использовано для получения или установки атрибута popover. Это может быть использовано для создания всплывающей подсказки с помощью JavaScript, а также полезно для обнаружения функций. Например:
function supportsPopover() {
return HTMLElement.prototype.hasOwnProperty("popover");
}
Аналогично:
-
HTMLButtonElement.popoverTargetElementиHTMLInputElement.popoverTargetElementобеспечивают эквивалент атрибутуpopovertarget, позволяя вам настроить кнопку(ы) управления для всплывающей подсказки, хотя значение свойства является ссылкой на элемент всплывающей подсказки DOM для управления. -
HTMLButtonElement.popoverTargetActionиHTMLInputElement.popoverTargetActionобеспечивают эквивалент глобальному HTML-атрибутуpopovertargetaction, позволяя вам указать действие, выполняемое кнопкой управления.
Объединив эти три элемента, вы можете программно настроить всплывающую подсказку и её управляющую кнопку, как показано ниже:
const popover = document.getElementById("mypopover");
const toggleBtn = document.getElementById("toggleBtn");
const keyboardHelpPara = document.getElementById("keyboard-help-para");
const popoverSupported = supportsPopover();
if (popoverSupported) {
popover.popover = "auto";
toggleBtn.popoverTargetElement = popover;
toggleBtn.popoverTargetAction = "toggle";
} else {
toggleBtn.style.display = "none";
}
У вас также есть несколько методов для управления отображением и скрытием:
-
HTMLElement.showPopover()для отображения всплывающей подсказки. -
HTMLElement.hidePopover()для скрытия всплывающей подсказки. -
HTMLElement.togglePopover()для переключения всплывающей подсказки.
Например, вы можете предоставить возможность переключать всплывающую подсказку справки включение/выключение щелчком по кнопке или нажатием определённой клавиши на клавиатуре. Первое можно реализовать декларативно, или же можно сделать это с помощью JavaScript, как показано выше.
Для второго можно создать обработчик событий, который программно обрабатывает две отдельные клавиши — одну для открытия всплывающей подсказки и другую для её закрытия:
document.addEventListener("keydown", (event) => {
if (event.key === "h") {
if (popover.matches(":popover-open")) {
popover.hidePopover();
}
}
if (event.key === "s") {
if (!popover.matches(":popover-open")) {
popover.showPopover();
}
}
});
В этом примере используется Element.matches() для программно проверки, отображается ли в настоящее время всплывающая подсказка. Псевдокласс :popover-open соответствует только всплывающим подсказкам, которые в настоящее время отображаются. Это важно, чтобы избежать ошибок, которые возникают при попытке отобразить уже отображаемую всплывающую подсказку или скрыть уже скрытую.
В качестве альтернативы, вы можете запрограммировать одну клавишу для отображения и скрытия всплывающей подсказки:
document.addEventListener("keydown", (event) => {
if (event.key === "h") {
popover.togglePopover();
}
});
Посмотрите наш пример переключения интерфейса справки (исходный код), чтобы увидеть свойства всплывающей подсказки JavaScript, обнаружение функций и метод togglePopover() в действии.
Вложенные всплывающие подсказки
Есть исключение из правила, что нельзя отображать несколько автоматических всплывающих подсказок одновременно — когда они вложены друг в друга. В таких случаях нескольким всплывающим подсказкам разрешается быть открытыми одновременно из-за их взаимосвязи. Эта модель поддерживается, чтобы обеспечить такие варианты использования, как вложенные меню всплывающих подсказок.
Существует три разных способа создания вложенных всплывающих подсказок:
-
Прямые дочерние элементы DOM:
<div popover> Parent <div popover>Child</div> </div>
-
Через вызов/элементы управления:
<div popover> Parent <button popovertarget="foo">Click me</button> </div> <div popover id="foo">Child</div>
-
Через атрибут
anchor:<div popover id="foo">Parent</div> <div popover anchor="foo">Child</div>
См. наш пример вложенного меню всплывающих подсказок (исходный код) для примера. Вы заметите, что было использовано довольно много обработчиков событий для отображения и скрытия подвсплывающей подсказки соответствующим образом во время доступа с помощью мыши и клавиатуры, а также для скрытия обоих меню при выборе параметра из любого из них. В зависимости от того, как вы обрабатываете загрузку нового контента, будь то в SPA или многостраничном веб-сайте, некоторые или все эти шаги могут быть не нужны, но они были включены в этот демонстрационный пример для наглядности.
Стиль всплывающих подсказок
API всплывающей подсказки содержит некоторые связанные CSS-функциональные возможности, которые стоит рассмотреть.
Что касается стилизации самой всплывающей подсказки, вы можете выбрать все всплывающие подсказки с помощью простого селектора атрибутов ([popover]), или вы можете выбрать всплывающие подсказки, которые отображаются, используя новый псевдокласс — :popover-open.
При рассмотрении первых нескольких примеров, связанных в начале статьи, вы, возможно, заметили, что всплывающие подсказки появляются посередине области просмотра. Это стандартная стилизация, достигаемая следующим образом в таблице стилей браузера:
[popover] {
position: fixed;
inset: 0;
width: fit-content;
height: fit-content;
margin: auto;
border: solid;
padding: 0.25em;
overflow: auto;
color: CanvasText;
background-color: Canvas;
}
Чтобы переопределить стандартные стили и разместить всплывающую подсказку в другом месте области просмотра, необходимо переопределить вышеуказанные стили, например, так:
:popover-open {
width: 200px;
height: 100px;
position: absolute;
inset: unset;
bottom: 5px;
right: 5px;
margin: 0;
}
Вы можете увидеть изолированный пример этого в нашем примере позиционирования всплывающей подсказки (исходный код).
Псевдоэлемент ::backdrop — это элемент, занимающий весь экран, размещённый непосредственно позади отображаемых элементов всплывающей подсказки в верхнем слое, что позволяет добавлять эффекты к содержимому страницы за всплывающей подсказкой(ами), если это необходимо. Например, вы можете затемнить содержимое за всплывающей подсказкой, чтобы привлечь внимание пользователя к ней:
::backdrop {
backdrop-filter: blur(3px);
}
Посмотрите наш пример размытия фона всплывающей подсказки (исходный код), чтобы понять, как это отображается.
Анимация всплывающих подсказок
Всплывающие подсказки устанавливаются в состояние display: none; при скрытии и в состояние display: block; при отображении, а также удаляются из / добавляются в верхний слой и дерево доступности. Поэтому, чтобы всплывающие подсказки анимировались, свойство display должно быть анимируемым. Поддерживающие браузеры анимируют display с вариантом типа анимации дискретной анимации. В частности, браузер будет переключаться между none и другим значением display, чтобы анимированное содержимое отображалось на протяжении всей анимации. Таким образом, например:
- При анимации
displayотnoneдоblock(или другого видимогоdisplayзначения), значение переключится наblockв0%процентах длительности анимации, чтобы оно оставалось видимым на протяжении всей анимации. - При анимации
displayотblock(или другого видимогоdisplayзначения) доnone, значение переключится наnoneв100%процентах длительности анимации, чтобы оно оставалось видимым на протяжении всей анимации.
Примечание: При анимации с использованием CSS-переходов, transition-behavior: allow-discrete необходимо установить, чтобы включить указанное поведение. При анимации с использованием CSS-анимаций, указанное поведение доступно по умолчанию; эквивалентный шаг не требуется.
Переход всплывающей подсказки
При анимации всплывающих подсказок с помощью CSS-переходов необходимы следующие функции:
-
@starting-styleпсевдоправило -
Обеспечивает набор начальных значений для свойств всплывающей подсказки, от которых происходит переход при первом отображении. Это необходимо для предотвращения неожиданного поведения. По умолчанию CSS-переходы происходят только тогда, когда свойство изменяется от одного значения к другому на видимом элементе; они не срабатывают при первом обновлении стиля элемента или при изменении типа
displayсnoneна другой тип. -
displayсвойство -
Добавьте
displayв список переходов, чтобы всплывающая подсказка оставалась видимой (display: blockили другим видимым значениемdisplay) на протяжении всего перехода, гарантируя видимость других переходов. -
overlayсвойство -
Включите
overlayв список переходов, чтобы отложить удаление всплывающей подсказки с верхнего слоя до завершения перехода, вновь гарантируя видимость перехода. -
transition-behaviorсвойство -
Установите
transition-behavior: allow-discreteдля переходовdisplayиoverlay(или для сокращённого свойстваtransition) для активации дискретных переходов этих двух свойств, которые по умолчанию не анимируются.
Давайте посмотрим на пример, чтобы вы увидели, как это выглядит:
HTML
HTML содержит элемент <div>, объявленный как всплывающая подсказка посредством глобального атрибута HTML popover, и элемент <button>, назначенный для управления отображением всплывающей подсказки:
<button popovertarget="mypopover">Show the popover</button> <div popover="auto" id="mypopover">I'm a Popover! I should animate.</div>
CSS
Два свойства всплывающей подсказки, которые мы хотим анимировать, это opacity и transform. Мы хотим, чтобы всплывающая подсказка поблескивала при горизонтальном увеличении или уменьшении. Для этого мы устанавливаем начальное состояние этих свойств для скрытого состояния элемента всплывающей подсказки (выбранного с помощью [popover] селектора атрибута) и конечное состояние для отображаемого состояния всплывающей подсказки (выбранного с помощью псевдокласса :popover-open). Мы также используем свойство transition, чтобы определить анимируемые свойства и продолжительность анимации при отображении или скрытии всплывающей подсказки.
html {
font-family: Arial, Helvetica, sans-serif;
}
/* Transition for the popover itself */
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}
[popover] {
font-size: 1.2rem;
padding: 10px;
/* Final state of the exit animation */
opacity: 0;
transform: scaleX(0);
transition:
opacity 0.7s,
transform 0.7s,
overlay 0.7s allow-discrete,
display 0.7s allow-discrete;
/* Equivalent to
transition: all 0.7s allow-discrete; */
}
/* Needs to be after the previous [popover]:popover-open rule
to take effect, as the specificity is the same */
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}
/* Transition for the popover's backdrop */
[popover]::backdrop {
background-color: rgb(0 0 0 / 0%);
transition:
display 0.7s allow-discrete,
overlay 0.7s allow-discrete,
background-color 0.7s;
/* Equivalent to
transition: all 0.7s allow-discrete; */
}
[popover]:popover-open::backdrop {
background-color: rgb(0 0 0 / 25%);
}
/* The nesting selector (&) cannot represent pseudo-elements
so this starting-style rule cannot be nested */
@starting-style {
[popover]:popover-open::backdrop {
background-color: rgb(0 0 0 / 0%);
}
}
Как обсуждалось ранее, мы также:
- Установили начальное состояние
transitionвнутри блока@starting-style. - Добавили
displayв список анимируемых свойств, чтобы анимируемый элемент оставался видимым (установленным в значениеdisplay: block) на протяжении всего процесса показа и скрытия всплывающей подсказки. Без этого анимация скрытия не отображалась бы, в результате всплывающая подсказка просто исчезала бы. - Добавили
overlayв список анимируемых свойств, чтобы гарантировать отсрочку удаления элемента с верхнего уровня до завершения анимации. Эффект этого может быть незаметен для простых анимаций, таких как эта, но в более сложных случаях опускание этого свойства может привести к удалению элемента из перекрытия до завершения перехода. - Установили
allow-discreteдля обоих свойств в указанных переходах, чтобы активировать дискретные переходы.
Вы заметите, что мы также включили переход для появления ::backdrop за всплывающей подсказкой при ее открытии, обеспечивая красивую анимацию затемнения.
Результат
Код отображается следующим образом:
Примечание: Поскольку всплывающие подсказки меняются с display: none на display: block каждый раз при отображении, анимация перехода всплывающей подсказки из @starting-style стилей в [popover]:popover-open стили происходит каждый раз при появлении элемента. При закрытии всплывающей подсказки она переходит из состояния [popover]:popover-open в стандартное состояние [popover].
В таких случаях переход стилей при появлении и скрытии может отличаться. Смотрите пример Демонстрация использования начальных стилей для доказательства этого.
Анимация всплывающей подсказки с ключевыми кадрами
При анимации всплывающей подсказки с помощью анимации CSS с ключевыми кадрами следует учесть некоторые различия:
- Вы не предоставляете
@starting-style; вы включаете значения "к" и "от"displayв ключевых кадрах. - Вы не явно включаете дискретную анимацию; нет эквивалента
allow-discreteвнутри ключевых кадров. - Вам также не нужно устанавливать
overlayвнутри ключевых кадров; анимацияdisplayобрабатывает анимацию всплывающей подсказки от показа до скрытия.
Давайте рассмотрим пример.
HTML
HTML содержит элемент <div>, объявленный как всплывающая подсказка, и элемент <button>, назначенный элементом управления отображением всплывающей подсказки:
<button popovertarget="mypopover">Show the popover</button> <div popover="auto" id="mypopover">I'm a Popover! I should animate.</div>
CSS
Мы определили ключевые кадры, которые задают желаемые анимации входа и выхода, а также анимацию входа только для фона. Обратите внимание, что анимировать затухание фона не представлялось возможным — фон сразу же удаляется из DOM при закрытии всплывающей подсказки, поэтому нет ничего, что можно было бы анимировать.
html {
font-family: Arial, Helvetica, sans-serif;
}
[popover] {
font-size: 1.2rem;
padding: 10px;
animation: fade-out 0.7s ease-out;
}
[popover]:popover-open {
animation: fade-in 0.7s ease-out;
}
[popover]:popover-open::backdrop {
animation: backdrop-fade-in 0.7s ease-out forwards;
}
/* Animation keyframes */
@keyframes fade-in {
0% {
opacity: 0;
transform: scaleX(0);
}
100% {
opacity: 1;
transform: scaleX(1);
}
}
@keyframes fade-out {
0% {
opacity: 1;
transform: scaleX(1);
/* display needed on the closing animation to keep the popover
visible until the animation ends */
display: block;
}
100% {
opacity: 0;
transform: scaleX(0);
/* display: none not required here because it is the default value
for a closed popover, but including it so the behavior is clear */
display: none;
}
}
@keyframes backdrop-fade-in {
0% {
background-color: rgb(0 0 0 / 0%);
}
100% {
background-color: rgb(0 0 0 / 25%);
}
}
Результат
Код отображается следующим образом:
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Popover_API/Using