Popover API を試してみる

オーバーレイメニュー、モーダルウィンドウのようなコンテンツの上に乗せて表示する表現をjsを使わなくても簡易に実装できるAPIです。

```html
<!-- これだけ！！ -->
<button popovertarget="MyPopover">
  ポップオーバーを表示・非表示
<button>
<div id="MyPopover" popover>
  ポップオーバーだよ
</div>
```

https://developer.mozilla.org/ja/docs/Web/API/Popover_API

2023年12月現在、最新のChrome, Safariで使用できますが、Safariは2023年9月にリリースされたバージョン17以降のため、今すぐ実践で使うのは少し難しい。

## できること

### htmlだけで十分な表示・非表示の制御ができる

こういう表示・非表示のUIは、ポップオーバー要素以外のクリックやESCキーによる非表示等をちゃんと作り込もうとするとやや面倒ですが、以下のような最低限の実装だけで要素以外のクリックとESCキーによる非表示が実装されます。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="mdvYPaj" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/mdvYPaj">
  Hello, popover</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

なお、表示だけのボタン、非表示だけのボタン、表示非表示のボタンは以下のようになります

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="poGmbpR" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/poGmbpR">
  Popover API - popovertargetaction</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### z-indexと関係なく、ページ最上部に表示できる

要素の重なり合いの制御はzindexのみでしたが、Popover APIで表示した要素はz-indexに関係なく最上部に表示されます。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="mdvYEYd" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/mdvYEYd">
  Popover要素は最強z-indexより上に表示される</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### 普通にスタイリングできる

popover属性はどんな要素に対してもあてることができて、スタイリングも普通にできます。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="RwvmGPN" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/RwvmGPN">
  Popover要素をスタイリング</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### ポップオーバー要素の外側の背景をcssだけで調整できる

ポップオーバーな表現は、下のコンテンツと異なるレイヤーであることをわかりやすくするために、半透明の要素を加えたりしますが、そのための要素をわざわざ加えずに、`::backdrop`疑似要素のスタイルを調整できます。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="ZEwNpbo" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/ZEwNpbo">
  Untitled</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### アニメーション

ポップオーバー要素はCSSでアニメーションを付けることができます。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="QWYRKga" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/QWYRKga">
  Popover アニメーション</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

↑のデモは表示時のみのアニメーションですが`:popover-open`疑似クラスを利用して非表示時のアニメーションも付けることもできそうだけど、時間ないので割愛。

### 制御ボタンの状態変化

ポップオーバー要素を制御するボタンに対して、表示中は押されてる感を演出したり、閉じる的な見た目にするのも、`:popover-open`疑似クラスとhasセレクターを使って実装できます。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="gOqJRQO" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/gOqJRQO">
  Popover 制御ボタンの状態変化</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## jsが必要なところ

### 初期状態であらかじめ表示

たとえばdetails要素はopen属性によって表示非表示が制御されてるので、open属性であらかじめ展開されてるdetails要素を作れますが、Popover APIにはそういう仕組になってないので`HTMLElement.showPopover()`を使って表示してあげます。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="XWOwKxE" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/XWOwKxE">
  Popover - あらかじめ表示</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### ポップオーバー以外の要素の非活性

ポップオーバー以外のリンクやボタンをクリックできなくしたり、フォーカスが当たらないようにするにはjsを使う必要があります。

<p class="codepen" data-height="300" data-default-tab="js,result" data-slug-hash="gOqJRyb" data-user="ksk1015" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ksk1015/pen/gOqJRyb">
  Hello, popover</a> by ksk1015 (<a href="https://codepen.io/ksk1015">@ksk1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>