JSを最小化せよ! Popover APIとAnchor Positioningで構築するモダンUI

ウェブ開発におけるUIコンポーネント、特にモーダルやツールチップ、コンテキストメニューの構築は、常に開発者の悩みの種でした。従来の解決策は、多くの場合、複雑なJavaScriptライブラリやフレームワークに依存しており、パフォーマンスのオーバーヘッドやメンテナンスの負担が増大するという課題がありました。しかし、近年、ウェブプラットフォーム自体の進化により、HTMLとCSSのみでこれらのUIをシンプルかつセマンティックに構築する道が開かれました。
この記事では、新しく登場したPopover APIとCSS Anchor Positioningという強力なブラウザネイティブ機能に焦点を当てます。これらを活用することで、最小限のJavaScriptで、アクセシビリティ(A11y)にも配慮したモダンなUIコンポーネントをいかに構築できるかを、具体的なコード例を交えて解説します。
この記事でわかること
- Popover APIの基本的な使い方と
popover
属性の役割 - CSS Anchor Positioningによる要素の相対的な位置決め方法
- JavaScriptを最小限に抑えながら、アクセシブルなUIを構築する実践的な方法
- よくある落とし穴と、それらを回避するためのヒント
- HTMLとCSSだけでモーダル、ツールチップ、メニューを実装するためのアプローチ
- どこまでがノーJSで実現でき、どこからJSが必要になるかの線引き
Popover APIとAnchor Positioningの基本
まず、Popover APIとAnchor Positioningの概念を理解しましょう。これらは密接に関連しながらも、異なる役割を持っています。
Popover API
Popover APIは、非モーダルなUIを構築するための新しいHTML属性です。これはdialog
要素が提供するモーダルな動作とは異なり、ページ内の他のコンテンツとのインタラクションを妨げません。popover
属性を要素に追加するだけで、その要素がポップオーバーとして機能するようになります。
<button popovertarget="my-popover">ツールチップを表示</button>
<div id="my-popover" popover>
これはツールチップです。
</div>
上記のコードでは、button
のpopovertarget
属性に、表示したいポップオーバーのIDを指定しています。このボタンをクリックすると、div
要素がポップオーバーとして自動的に表示・非表示されます。JavaScriptを一切書かずにポップオーバーの表示を制御する、これが基本的な方法です。
CSS Anchor Positioning
CSS Anchor Positioningは、特定の要素(ポップオーバーなど)を、別の要素(アンカー)に対して相対的に配置するための新しいCSS機能です。これにより、要素の絶対的な位置を計算するためにJavaScriptを使う必要がなくなります。
anchor-name
というCSSプロパティをアンカー側に付与し、位置決めされる側でanchor()
関数を使って位置を決定します。Popover APIと組み合わせる場合、popovertarget
で紐づけられたボタンが暗黙のアンカーになるという特別な挙動があります。このため、anchor-name
を明示的に指定しなくても、ボタンを基準にポップオーバーを配置できます。
明示的なアンカー名を使う場合
位置決めされる側で明示的にposition-anchor
プロパティを使って、どのアンカーを基準にするかを指定します。
<button class="my-anchor" popovertarget="my-popover">ツールチップを表示</button>
<div id="my-popover" popover class="popover">これはツールチップです。</div>
/* アンカー側の要素に anchor-name を付与 */
.my-anchor {
anchor-name: --my-anchor;
}
/* 位置決めされる側で関連付けプロパティ position-anchor を追加 */
#my-popover {
position: absolute;
position-anchor: --my-anchor;
top: anchor(bottom);
left: anchor(center);
translate: -50% 0;
}
実践! シンプルなツールチップとメニューの構築
ここでは、Popover APIとAnchor Positioningを組み合わせて、より実践的なUIコンポーネントを構築する方法を見ていきましょう。
ツールチップの完全な例
以下は、HTMLとCSSだけで、はみ出しを考慮して自動で位置を調整するツールチップの完全な例です。なお、ポップオーバーはユーザーエージェントの既定スタイルで position: fixed
となり、画面中央に配置されるため、これを打ち消す必要があります。この例では、popovertarget
で紐づけられたボタンを暗黙のアンカーとして利用しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<style>
body {
padding: 50px;
}
/* Popover のデフォルトスタイルをリセット */
.tooltip {
margin: 0;
inset: auto;
position: absolute;
}
/* ポジションの候補を定義 */
@position-try --tooltip-top {
bottom: anchor(top);
left: anchor(center);
translate: -50% 0;
}
@position-try --tooltip-bottom {
top: anchor(bottom);
left: anchor(center);
translate: -50% 0;
}
.tooltip {
position-try: --tooltip-bottom, --tooltip-top;
}
</style>
</head>
<body>
<button popovertarget="my-tooltip">
クリックしてね
</button>
<div id="my-tooltip" class="tooltip" popover="auto">
<p>これがツールチップです。</p>
</div>
</body>
</html>
トラブル時のチェックポイント
- ブラウザ対応状況の確認: Popover APIはすでに主要なブラウザで広く利用可能ですが、CSS Anchor Positioningはまだ限定的なサポートに留まっています。実装前にCan I use...で最新の対応状況を確認しましょう。
- ポップオーバーが表示されない?:
popover
属性が正しく設定されているか、またpopovertarget
属性のIDがpopover
を持つ要素のIDと一致しているか確認しましょう。 - 意図しない位置に表示される?: Popoverはデフォルトで画面中央に配置されるため、
margin: 0; inset: auto; position: absolute;
でデフォルトスタイルをリセットし、anchor()
関数で明示的な位置決めを行う必要があります。 - よくあるミス:
popover
属性のつけ忘れ、anchor-name
のスペルミス、HTMLにおけるIDの重複など、基本的なミスが原因であることが多いです。
どこで使える?ユースケースのヒント
- フォームのバリデーションエラー表示: ユーザーが入力ミスをした際に、関連する入力フィールドの近くにポップオーバーでエラーメッセージを表示します。
- インライン編集のヒント: テキストの近くに、編集やフォーマットのオプションを含む小さなポップアップを表示します。
- スマホUIでの挙動: 画面サイズが小さい場合でも、Anchor Positioningが自動的に最適な位置に調整してくれるため、メディアクエリを多用した位置調整が不要になります。
- 開閉時のスタイル制御: 開いているポップオーバーにスタイルを適用したい場合は、
:popover-open
疑似クラスが便利です。
アクセシビリティの深掘りと「あえてJSを書くなら」の境界線
Popover APIは、ポップオーバー要素自体に role
を自動付与しません。ただし、popovertarget
で結びついた呼び出し元(ボタン)には、aria-expanded
や aria-details
といった状態・関係が対応ブラウザでは自動で付与され、キーボードフォーカス移動も適切に制御されます。したがって、必要に応じて role="tooltip"
や role="menu"
などは手動で指定してください。
- セマンティクスは手動で: 用途に応じて
role="tooltip"
やrole="menu"
などを手動で付与する必要があります。 aria-describedby
: ツールチップとそれをトリガーする要素を関連付けるために、この属性を手動で付加すると良いでしょう。- キーボードナビゲーション: メニュー内のアイテムを矢印キーで移動するような操作は、現時点ではJavaScriptでの実装が必須です。
- 動的なコンテンツの生成: データベースから取得したデータに基づいて動的にポップオーバーの内容を生成したり、複数の要素を同時に操作したりする場合も、JavaScriptの出番です。
これらの線引きを理解することで、「どこまでをネイティブ機能に任せるか」という判断が明確になります。
まとめ
この記事では、ウェブ開発のUI構築における新しいアプローチとして、Popover APIとCSS Anchor Positioningを紹介しました。これらは、従来の複雑なJavaScriptに依存したソリューションから脱却し、よりシンプルでパフォーマンスの高い、そしてアクセシビリティに優れたUIコンポーネントを構築するための強力なネイティブ機能です。
これらの機能を活用することで、開発者はHTMLとCSSを「UIの振る舞いを定義する言語」として捉え直すことができます。これにより、JavaScriptの役割は、UIのロジックや動的なデータ操作といった、より複雑なタスクに集中させることが可能になります。
この記事が、あなたのウェブ開発におけるUI構築の理解を深める一助となれば幸いです。ご覧いただきありがとうございました。