ポップオーバーAPIを攻略する 第1回 ポップオーバーAPIの基本の使い方とスタイリング

ポップオーバーを表示するための標準的な仕組みであるポップオーバーAPIについて解説します。今回は基本的な使い方とスタイリングについて解説します。

発行

著者 坂巻 翔大郎 フロントエンド・エンジニア
ポップオーバーAPIを攻略する シリーズの記事一覧

はじめに

ウェブサイトやウェブアプリにおいて、ダイアログやツールチップ、チュートリアルのUIのように、コンテンツの上にかぶさって表示されるUIが頻出します。そういったものを本記事では「ポップオーバー」と呼び、そのポップオーバーを表示するための標準的な仕組みを「ポップオーバーAPI」と呼びます。

ポップオーバーAPIは、ポップオーバーの制御をHTMLの属性で宣言したり、JavaScriptを使うことで制御できます。

本シリーズでは、ポップオーバーAPIの基本から、実践的な用法まで解説します。

コンテンツの上にかぶさって表示されるUI

前述のとおり、ポップオーバーには、モーダルダイアログ、トースト、ツールチップ、チュートリアルのUI、ポップアップと、さまざまなものがありますが、どれにも共通するのは、コンテンツの上にかぶさって表示されるUIです。それらに共通するポップオーバーの要件として挙げられるのは、次のものです。

  • クリックやホバーなどユーザーのアクションがきっかけで表示される
  • コンテンツの上にかぶさって表示される
  • UIの外側をクリックすると閉じられる(ものが多い)

これらを普通に実装するためには、CSSやJavaScriptを使って、ポップオーバーを表示・非表示するための仕組みを作る必要があります。

「コンテンツの上にかぶさる」ということは、重なり順が重要です。すると、z-indexのことを考えなくてはいけません。外側をクリックしたら閉じるだけでなく、Escキーを押したら閉じる、といったような使い勝手を良くするための工夫も必要です。これはかなり煩雑になりそうです。

そこで、標準の機能であるポップオーバーAPIを使います。ポップオーバーAPIは、任意の要素をポップオーバーとして、紐づけたボタンから表示・非表示をできるようにするものです。ポップオーバーにしたい要素と、ポップオーバーを呼び出すボタンに特定の属性に指定することで、ポップオーバーに必要な要件を満たした実装ができるのです。

基本の使い方

ポップオーバーAPIの使い方は簡単です。ポップオーバーにしたい要素と、ポップオーバーを呼び出すための要素に必要な属性を指定するだけです。それだけでボタンをクリックしたらポップオーバーが表示されます。

基本的な構文

<div id="my-popover" popover>ポップオーバーの中身</div>
<button popovertarget="my-popover">ポップオーバーを開閉する</button>

たったこれだけで、JavaScriptを使わずとも、必要な要件を満たしたポップオーバーができてしまいました。

では、より詳細にポップオーバーAPIの使い方を、次の2つに分けてそれぞれ解説します。

  1. 任意の要素をポップオーバーにする
  2. ポップオーバーを表示するボタン

任意の要素をポップオーバーにする

まず、ポップオーバーにしたい要素にid属性とpopover属性を付与します。id属性はポップオーバーを呼び出すためのボタンを紐づけるためのもので、一意な値を指定します。

基本的な構文

<div id="my-popover" popover>ポップオーバーの中身</div>

任意の要素にpopover属性を指定することでポップオーバーになります。popover属性にはポップオーバーの状態を指定するための値を指定できます。

現状広く実装されている属性値のうち、指定できるものはautomanualです。属性値を指定しない場合はデフォルト値のautoが使用されます。

popover属性値の拡大

今回紹介するautomanualでは表現できないUIを実装できるように、ポップオーバー関連APIには継続的に仕様が追加されています。今回は実装が主要エンジンすべてで終わったばかりの、最小限のAPIについて解説します。

popover属性値:auto

popover属性にautoを設定

<div id="my-popover-1" popover>ポップオーバーの中身</div>
<div id="my-popover-2" popover="auto">ポップオーバーの中身</div>

autoの場合は、ポップオーバーが開かれたときに、すでに開いているポップオーバーを強制的に閉じる動作となります。さらにLight Dismissが有効になります。

Light Dismissとは簡易非表示のことです。popover属性の値がない、またはautoのとき、Light Dismissが有効になり、次のことができるようになります。

  • ポップオーバーが開いたときに、すでに開いているautoのポップオーバーを強制的に閉じる
  • Escキーでポップオーバーを閉じる
  • ポップオーバーの外側をクリックでポップオーバーを閉じる

JavaScriptを使用せずとも、これらのことができるのはとてもありがたいものです。

popover属性値:manual

popover属性にmanualを設定

<div id="my-popover-4" popover="manual">ポップオーバーの中身</div>

manualの場合は、ポップオーバーが表示されたときに他のポップオーバーを閉じません。ポップオーバーは複数表示できるようになります。Light Dismissは無効になります。無効の場合は、次のようになります。

  • ポップオーバーが開いたときに、すでに開いているポップオーバーを閉じない
  • Escキーを押してもポップオーバーを閉じない
  • ポップオーバーの外側をクリックしてもポップオーバーは閉じない

ポップオーバーを表示するボタン

ポップオーバーを操作するボタン要素には、popovertarget属性とpopovertargetaction属性の2つの属性が指定できます。

制御するポップオーバーを指定するpopovertarget属性

popovertarget属性は、制御したいポップオーバーのid属性値を指定します。

popovertarget属性にid属性値を指定

<button popovertarget="my-popover-1">ポップオーバーを開閉する</button>
<div id="my-popover-1" popover>ポップオーバーの中身</div>

popovertarget属性が指定できるのは、button要素またはtype="button"を持つinput要素です。

ポップオーバーの開閉動作を指定するpopovertargetaction属性

popovertargetaction属性は、ポップオーバーの開閉動作を指定します。属性値に指定できるものは、toggleshowhideの3つです。

  • toggle:ポップオーバーが閉じていれば開く、開いていれば閉じる(デフォルト値)
  • show:ポップオーバーを開く
  • hide:ポップオーバーを閉じる

popovertargetaction属性の動作

<div id="my-popover-1" popover>ポップオーバーの中身</div>

<button popovertarget="my-popover-1" popovertargetaction="toggle">
  ポップオーバーを開閉する
</button>

<button popovertarget="my-popover-1" popovertargetaction="show">
  ポップオーバーを開く
</button>

<button popovertarget="my-popover-1" popovertargetaction="hide">
  ポップオーバーを閉じる
</button>

popovertargetaction属性を指定しなかった場合は、デフォルト値のtoggleが使用されます。

ポップオーバーに関連する擬似要素と擬似クラス

ポップオーバーAPIのメリットのひとつに、スタイリングのしやすさがあります。従来はポップオーバーのカスタマイズを行うにはそれなりの手間がかかりました。しかし、ポップオーバーAPIにはスタイリングに使用できる仕組みも用意されていますので、スタイリングが比較的容易にできます。

ポップオーバー自体のスタイル:[popover]

ポップオーバーのUA(ユーザーエージェント)スタイルは次のようになっています。

ポップオーバーのUAスタイル

[popover] {
  position: fixed;
  width: fit-content;
  height: fit-content;
  color: canvastext;
  background-color: canvas;
  inset: 0px;
  margin: auto;
  border-width: initial;
  border-style: solid;
  border-color: initial;
  border-image: initial;
  padding: 0.25em;
  overflow: auto;
}
[popover]:popover-open:not(dialog) {
  overlay: auto !important;
}
[popover]:not(:popover-open):not(dialog[open]) {
    display: none;
}

ポップオーバーである要素には、popover属性が付与されているため、[popover]属性セレクターを使用します。

ポップオーバーが開かれているときには、次に紹介する:popover-open擬似クラスを組み合わせます。

ポップオーバーが開いているときのスタイル::popover-open擬似クラス

:popover-open擬似クラスは、ポップオーバーが開かれているときに適用される擬似クラスです。ポップオーバーが開かれているときのスタイルを変更するために使用できます。

ポップオーバーが開いているときのスタイル指定

[popover]:popover-open {
  top: 100px;
  left: 100px;
  width: 200px;
  height: 200px;
}

ポップオーバーとなった要素は、閉じているとき(:popover-open擬似クラスが適用されていないとき)は、display: none;が適用されているため画面には表示されません。

ですが、ポップオーバーの要素でFlexboxやCSS Gridを使おうとして、次のようなスタイルを書いてしまうと、ポップオーバーが閉じているときでも表示されてしまいます。

displayプロパティをnone以外の値に設定

[popover] {
  display: flex; /* display: none; 以外の値 */
}

このようなことをしたい場合は、:popover-open擬似クラスを使ってスタイルを指定するようにしましょう。:popover-open擬似クラスを使用すれば、前述したように「開いているとき」しか適用されません。したがって、displayプロパティにnone以外の値を設定しても、閉じているときには影響しません。

flexを設定しても閉じているときには影響しない

[popover]:popover-open {
  display: flex;
}

ポップオーバーが開いているときの背景のスタイル:::backdrop擬似要素

::backdrop擬似要素は、トップレイヤーにあるポップオーバーの後ろに配置される全画面要素です。

デフォルトでは次のUAスタイルが適用されています。

デフォルトのUAスタイル(抜粋)

[popover]:-internal-popover-in-top-layer::backdrop {
  position: fixed;
  background-color: transparent;
  pointer-events: none !important;
  inset: 0px;
}

UAスタイルをみると、なんらかは全画面に表示されていますが、background-color: transparent;ですから、透明で見えないようになっています。

この::backdrop擬似要素は、ポップオーバーに注目させるために、ポップオーバーの後ろのコンテンツをぼかしたり、暗くしたりするために使用できます。

背後のコンテンツを灰色にぼかす

[popover]::backdrop {
  backdrop-filter: blur(3px);
  background-color: rgba(0,0,0,0.1);
}

次のデモで確認できます。

デモでは、あたかも後ろのコンテンツに触ることができないように見えますが、ポップオーバーAPIを使用して作成したポップオーバーは非モーダルです。したがって、後ろにある要素はマウスオーバーやクリックでも反応します。

補足:後ろの要素を反応させたくない

後ろの要素に反応してほしくない場合、つまりポップオーバー以外のことができなくしたいというのであれば、それは「モーダル」なのです。その場合は、dialog要素のdialog.showModal()を使用することになります。

ここまでのまとめ

今回は、ポップオーバーAPIの基本的な使い方と、スタイリングについて解説しました。相応しいケースでポップオーバーAPIを使うと、実装がぐっと楽になることがおわかりいただけたかと思います。

次回は、さまざまなコンテンツをかぶさって表示される、ポップオーバーの重なり順について解説します。