CSS アンカー ポジショニングを使用してツールチップやポップオーバーを構築する場合、ビューポートからオーバーフローする可能性がある場合は、ブラウザが要素をフォールバック位置に自動的に「反転」させることができます。このような場合は、配置されたコンテンツのスタイルを調整して、配置されたコンテンツからアンカーを指す矢印の位置を変更することをおすすめします。
アンカー コンテナクエリは、要素のアクティブな位置指定状態をクエリし、それに応じてスタイルを適用できるようにすることで、この問題を解決します。ビューポートの衝突反転(方向矢印のスタイル変更なし)を使用した一般的なアンカー付きドロップダウンとフライアウトの配置については、ビューポート対応ドロップダウンをご覧ください。
問題
デフォルトでアンカーの上に表示されるツールチップを考えてみましょう。下部に下向き矢印があります。ユーザーがスクロールして、ツールチップが反転してアンカーの下に表示されると、矢印は間違った方向を指し、ツールチップの間違った側に表示されます。
解決策: アンカー付きコンテナクエリ
配置された要素に container-type: anchored を設定すると、その要素は独自のアンカー配置状態を認識するクエリコンテナになります。その後、@container anchored() クエリを使用して、その子孫または疑似要素を更新できます。
1. ツールチップとトリガーを作成する
Popover API を使用してツールチップを作成します。popovertarget を介してポップオーバーを呼び出すと、トリガーボタンとの暗黙的なアンカー接続が自動的に確立されるため、明示的な anchor-name や position-anchor は必要ありません。
<button popovertarget="tooltip" id="anchor" aria-describedby="tooltip">anchor</button>
<div id="tooltip" popover role="tooltip"></div>
アンカーの配置で使用するポップオーバーのインセットとマージンのスタイルをリセットします(アンカーの配置がサポートされている場合のみ)。
@supports (anchor-name: --my-anchor) {
[popover] {
inset: auto;
margin: unset;
}
}
2. コンテナをセットアップする
配置する要素に container-type: anchored を適用します。この要素には、反転動作を有効にするために position-try-fallbacks も定義する必要があります。
#tooltip {
position: fixed;
position-area: block-start;
position-try-fallbacks: flip-block;
/* Enable anchored container queries */
container-type: anchored;
}
3. フォールバックに基づくスタイル
特定のフォールバックが有効な場合にスタイルを適用するには、@container anchored(fallback: <value>) を使用します。
すべてのコンテナクエリと同様に、@container はコンテナの子孫にのみスタイルを設定できます。矢印を作成する一般的な方法は、::before 疑似要素と ::after 疑似要素を使用することです。これらは子孫として扱われ、直接スタイルを設定できます。ただし、ツールチップ自体をスタイル設定するには(ステップ 4 を参照)、ツールチップに子要素を追加し、その ::before 疑似要素に矢印を作成します。
<div id="tooltip" popover role="tooltip">
<div class="tooltip-content">Tooltip</div>
</div>
.tooltip-content::before {
/* Default "down" arrow for the 'top' position */
content: "▼";
position: absolute;
inset-block-end: 0;
inset-inline-start: 1rem;
}
/* Update to an "up" arrow when the 'flip-block' fallback (bottom) is active */
@container anchored(fallback: flip-block) {
.tooltip-content::before {
content: "▲";
inset-block-start: 0;
inset-block-end: auto;
}
}
4. コンテナ自体のスタイル設定
反転時にコンテナ自体のプロパティ(margin や background-color など)を変更する必要がある場合は、内部ラッパー要素を使用する必要があります。
- 外側に配置された要素に
container-type: anchoredを適用します。 @containerブロック内の内部要素をターゲットにします。
@container anchored(fallback: flip-block) {
.tooltip-content {
border-radius: 0 0 .5rem .5rem;
margin-block-start: 0.25rem;
}
}
ベスト プラクティス
- 論理的なフォールバックを優先する:
position-try-fallbacksでflip-blockやflip-inlineなどのキーワードを使用すると、RTL やさまざまな記述モードを自動的に処理するシンプルなクエリを作成できます。 - 矢印に疑似要素を使用する: ツールチップの矢印は純粋に装飾的なものであり、
::beforeまたは::afterの候補として最適です。これらは、追加の DOM なしでアンカー付きコンテナクエリを介してスタイル設定できます。
代替戦略
適用されたフォールバックに基づいて矢印を配置することはプログレッシブ エンハンスメントであり、フォールバック位置に対応する別の方法はありません。アンカー位置コンテナクエリをサポートしていないブラウザで矢印を非表示にするには、@supports (container-type: anchored) で CSS のサポートをテストします。
@supports (container-type: anchored) {
.tooltip-content::before {
content: "▼";
}
}
Popover のフォールバックとブラウザ サポート
Popover API は主にプログレッシブ エンハンスメントですが、その定義動作である最上位レイヤのプロモーション、ライトディスミス、popovertarget 呼び出しには、CSS のみの同等の機能がありません。古いブラウザでは、ポリフィルが必要です。ポリフィルを配布したくない場合は、手動でフォールバックする必要があります。
ポリフィル: 古いブラウザで popover 属性をサポートするには、条件付きで @oddbird/popover-polyfill を読み込みます。必須: HTMLElement.prototype の popover プロパティをチェックして機能を検出し、ネイティブ サポートがない場合にのみポリフィルを読み込みます。無条件に読み込まないでください。
バンドラまたはインポート マップを使用する場合:
// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
import("@oddbird/popover-polyfill");
}
バンドラを使用しない場合は、<script type="module"> 内の CDN からインポートします。
<script type="module">
if (!("popover" in HTMLElement.prototype)) {
import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
}
</script>
スタイリングに関する注意事項: ポリフィルは実際の :popover-open 疑似クラスを定義できないため、代わりに .\:popover-open クラスを適用します。必須: :is() または :where() を使用して 2 つを結合します。そうしないと、:popover-open がないブラウザではルール全体が破棄されます。
[popover]:is(:popover-open, .\:popover-open) {
display: block;
}
または、ポリフィルを使用しないレガシー フォールバックの場合は、position: fixed を使用して getBoundingClientRect() で座標を手動で計算するか、ユースケースで許容される場合は inset: auto でデフォルトの配置を使用します。
Popover API をサポートしていないブラウザは、アンカーの配置もサポートしていないため、ツールチップは画面の中央に表示されます。