Клавиша / esc

Popover API

Нативный способ создавать всплывающие элементы.

Время чтения: 6 мин

Кратко

Скопировано

Удобный способ создавать всплывающие элементы. Новая возможность HTML. Имеет много встроенных фишек типа закрытия по клику на странице или по нажатию клавиши Esc.

Можно управлять как при помощи атрибутов HTML, так и через JavaScript.

Пример

Скопировано
        
          
          <button  popovertarget="my-popover"  popovertargetaction="toggle">  Всплываем!</button><div id="my-popover" popover>  <p>🛳️</p></div>
          <button
  popovertarget="my-popover"
  popovertargetaction="toggle"
>
  Всплываем!
</button>

<div id="my-popover" popover>
  <p>🛳️</p>
</div>

        
        
          
        
      

Как понять

Скопировано

Поповер — это любые всплывающие элементы в интерфейсе: всплывающие подсказки (тултипы), раскрывающиеся меню, превью товаров и другие.

В веб-дизайне есть большая группа оверлеев (overlays). Это любой элемент, который появляется поверх остального содержимого интерфейсов. Дальше, внутри оверлеев, круг элементов сужается до более конкретных попапов (popups). Обычно это небольшие окна, которые появляются автоматически. Вот тут-то и появляются поповеры, а ещё диалоговые окна (привет, <dialog>).

Схема устройства оверлеев и поповеров, подробное описание перед ней.

Долгое время в HTML не существовало простого способа реализовать поповеры. Самодельные решения требовали большого внимания к мелочам, часто не учитывали всех сценариев использования и были недоступными. Теперь, при помощи нескольких атрибутов, можно создать удобный и доступный для всех всплывающий элемент.

Преимущества:

  • всплытие на верхний уровень — элемент всегда будет отображаться выше всех остальных, больше не нужно возиться с z-index;
  • простое закрытие — клик за пределами элемента закроет его и вернёт фокус на последний активный элемент на странице;
  • фокус внутри поповера — при использовании клавиатуры следующий элемент, попавший в фокус, будет внутри поповера;
  • поддержка клаватуры — по нажатию на клавишу Esc поповер закроется;
  • семантическая связь — привязка поповера к элементу, который её вызывает.

Как пишется

Скопировано

Обязательные атрибуты

Скопировано
  • popover — указывает, что блок теперь ведёт себя как поповер;
  • id — уникальный идентификатор блока, используется для показа поповера;
  • popovertarget — связывает элемент, например, кнопку или другой HTML-тег, с поповером. В качестве значения используется id элемента, который хотим показать.
        
          
          <button popovertarget="my-popover">  Показать поповер</button><div id="my-popover" popover>  <p>Я — простой, но крутой поповер 😎</p></div>
          <button popovertarget="my-popover">
  Показать поповер
</button>

<div id="my-popover" popover>
  <p>Я — простой, но крутой поповер 😎</p>
</div>

        
        
          
        
      
Открыть демо в новой вкладке

Кнопка закрытия

Скопировано

По умолчанию элемент с popovertarget открывает и закрывает поповер. Это поведение можно изменить с помощью атрибута popovertargetaction.

Возможные значения:

  • toggle — значение по умолчанию, применяется, если атрибут не прописан. Переключает состояние поповера между открытым и закрытым;
  • show — открывает поповер;
  • hide — закрывает поповер.

Таким образом, можно создать отдельные кнопки для открытия и закрытия элемента.

В примере ниже кнопка «Показать поповер» будет только открывать всплывающий элемент, но не закрывать его. Для закрытия внутрь добавлена соответствующая кнопка.

        
          
          <button popovertarget="my-popover" popovertargetaction="show">  Показать поповер</button><div id="my-popover" popover>  <button popovertarget="my-popover" popovertargetaction="hide">    <span aria-hidden="true">❌</span>    <span class="sr-only">Закрыть</span>  </button>  <p>Я — поповер, который нельзя закрыть той же кнопкой</p></div>
          <button popovertarget="my-popover" popovertargetaction="show">
  Показать поповер
</button>

<div id="my-popover" popover>
  <button popovertarget="my-popover" popovertargetaction="hide">
    <span aria-hidden="true"></span>
    <span class="sr-only">Закрыть</span>
  </button>

  <p>Я — поповер, который нельзя закрыть той же кнопкой</p>
</div>

        
        
          
        
      
Открыть демо в новой вкладке

Значения popover

Скопировано

На самом деле у атрибута popover есть два значения:

  • auto — значение по умолчанию, не требуется прописывать явно. Одновременно показывается только один. Поповер может быть закрыт по клику за пределами элемента;
  • manual — можно показать несколько одновременно. Поповер не может быть закрыт по клику за его пределами.

В демо ниже два поповера с разными значениями. Покликайте по ним, посмотрите на разницу в их поведении.

        
          
          <button popovertarget="popover-auto">  <code>popover="auto"</code></button><div id="popover-auto" popover="auto">  <p>Закрываю другие всплывашки. Легко закрываюсь сам.</p></div><button popovertarget="popover-manual">  <code>popover="manual"</code></button><div id="popover-manual" popover="manual">  <p>Не закрываю другие. Без кнопки не закроюсь.</p></div>
          <button popovertarget="popover-auto">
  <code>popover="auto"</code>
</button>

<div id="popover-auto" popover="auto">
  <p>Закрываю другие всплывашки. Легко закрываюсь сам.</p>
</div>

<button popovertarget="popover-manual">
  <code>popover="manual"</code>
</button>

<div id="popover-manual" popover="manual">
  <p>Не закрываю другие. Без кнопки не закроюсь.</p>
</div>

        
        
          
        
      
Открыть демо в новой вкладке

Стилизация

Скопировано

Стили поповера по умолчанию:

        
          
          [popover] {  position: fixed;  width: fit-content;  height: fit-content;  inset: 0px;  margin: auto;  border: solid;  padding: 0.25em;}
          [popover] {
  position: fixed;
  width: fit-content;
  height: fit-content;
  inset: 0px;
  margin: auto;
  border: solid;
  padding: 0.25em;
}

        
        
          
        
      

Переопределяйте их по необходимости.

Можно стилизовать подложку открытого поповера при помощи псевдокласса ::backdrop.

        
          
          [popover]::backdrop {  background-color: rgb(255 255 255 / 0.5);}
          [popover]::backdrop {
  background-color: rgb(255 255 255 / 0.5);
}

        
        
          
        
      
Открыть демо в новой вкладке

Анимации

Скопировано

Можно анимировать открытие и закрытие всплывающего элемента. Для этого потребуется описать несколько состояний.

При помощи директивы @starting-style задаём стили, от которых будет начинаться анимация открытия:

        
          
          @starting-style {  [popover]:popover-open {    opacity: 0;    rotate: 1turn;  }}
          @starting-style {
  [popover]:popover-open {
    opacity: 0;
    rotate: 1turn;
  }
}

        
        
          
        
      

Затем прописываем стили для открытого элемента:

        
          
          [popover]:popover-open {  opacity: 1;  rotate: 0turn;  transition: rotate .5s, opacity .5s, display .5s, overlay .5s;}
          [popover]:popover-open {
  opacity: 1;
  rotate: 0turn;
  transition: rotate .5s, opacity .5s, display .5s, overlay .5s;
}

        
        
          
        
      

И в конце пишем конечные стили при закрытии окна:

        
          
          [popover]:not(:popover-open) {  scale: 0;  transition: scale .3s, display .3s, overlay .3s;}
          [popover]:not(:popover-open) {
  scale: 0;
  transition: scale .3s, display .3s, overlay .3s;
}

        
        
          
        
      

Обратите внимание на свойство overlay, которое используется внутри transition. Это ключевое слово необходимо для анимации всплытия элемента из верхнего слоя.

Открыть демо в новой вкладке

Отличия от <dialog>

Скопировано

В чём отличие поповера от такого же нового <dialog>? Кажется, что оба создают всплывающие окна.

Сам по себе элемент с атрибутом popover не несёт никакой семантической нагрузки. Вы можете самостоятельно добавить ему нужного смысла при помощи ARIA-ролей. К примеру, tooltip.

Диалог, открытый в режиме модального окна, не может быть закрыт по клику за пределами элемента. Поповер, напротив, поддерживает такую возможность.

Также модальное окно блокирует остальную страницу под ним. Поповер так не поступает.

Методы JavaScript

Скопировано

Для большинства сценариев работы с поповерами совсем не нужен JavaScript. Если есть такая необходимость, используйте следующие методы:

  • .showPopover() — открыть поповер.
  • .hidePopover() — закрыть поповер.
  • .togglePopover() — переключить состояние поповера между открытым и закрытым.
        
          
          document.getElementById('my-popover').showPopover()
          document.getElementById('my-popover').showPopover()

        
        
          
        
      

Проверить, что поповер открыт, можно при помощи .matches(':popover-open'), .checkVisibility() или event.newState === 'open'.