
CSS Anchor Positioningとは ― ツールチップやPopoverの位置計算をCSSに任せる仕組み
ツールチップ、ドロップダウン、補足カード、右クリックメニュー。これらのUIは「ボタンの近くに出す」だけなら簡単そうに見えます。しかし実装では、スクロール、画面幅、拡大表示、文章量、親要素の位置指定、画面端からのはみ出しまで考えなければなりません。そのため従来は、JavaScriptで基準要素の座標を測り、表示位置を計算し直す実装が広く使われてきました。
CSS Anchor Positioning は、ボタンや入力欄を基準にして、ツールチップなどの表示位置をCSSで決める仕組みです。基準にした要素が動けば表示も追従し、画面端で収まらないときは別の位置を試せます。2026年時点でブラウザへの実装は進んでいますが、仕様はまだW3C Working Draftです。この記事では、何ができるのか、Popover APIとどう組み合わせるのか、どこまでJavaScriptの座標計算を減らせるのかを整理します。
CSS Anchor Positioningは何を解決するのか
W3Cの仕様では、位置指定された要素が、ページ上の別の「アンカー要素」を基準に自分の大きさや位置を決められる仕組みとして説明されています。ここでいうアンカー要素とは、表示位置の基準になる要素です。ツールチップなら、説明対象のボタンや入力欄がアンカーに当たります。
対象になるのは、次のような「ほかの内容より前面に表示され、特定の要素の近くに置きたいUI」です。
- アイコンや入力欄に付くツールチップ、エラーメッセージ
- ボタンから開くドロップダウン、Popover、設定パネル
- 選択範囲の近くに出す書式ツールバー
- 商品やグラフの要素に追従する補足カード
これまでのCSSでも、親要素を position: relative、子要素を position: absolute にすれば近くへ置けました。難しかったのは、配置する要素がDOM上で離れた場所にある場合、Popoverのようにほかの内容より前面のtop layerへ出す場合、画面端で上下左右を切り替えたい場合です。Anchor Positioningは、DOMの親子関係だけに頼らず「どの要素を位置の基準にするか」をCSSで指定できます。
従来のJavaScript配置は何をしていたのか
従来の実装では、getBoundingClientRect() などでボタンの座標と大きさを取得し、Popoverの幅と高さ、ブラウザ画面の空き領域を比較して、top と left を決めるのが一般的でした。スクロールや画面サイズの変更が起きれば、再計算も必要です。
const anchorRect = button.getBoundingClientRect();
const popupRect = popup.getBoundingClientRect();
const fitsAbove = anchorRect.top >= popupRect.height + 8;
popup.style.top = fitsAbove
? anchorRect.top - popupRect.height - 8 + "px"
: anchorRect.bottom + 8 + "px";
実際の配置ライブラリは、スクロール領域、拡大率、右から左へ書く言語、変形された要素、吹き出しの矢印、ほかの要素との重なりなども扱います。したがって「数行の座標計算で十分」とは限りません。CSS Anchor Positioningを使うと、ボタンへの追従や「どの位置なら画面内に収まるか」の判断をブラウザへ任せられます。
ただし、配置ライブラリが即座に不要になるわけではありません。対応ブラウザ、複雑な衝突回避、アニメーション、既存コンポーネントとの統合によっては、JavaScriptの実装が今も適切です。
基本はアンカー、関連付け、配置の3段階
明示的な関連付けを使う場合、考えることは3つです。まず基準要素に名前を付け、次に浮かせる要素からその名前を参照し、最後に基準のどこへ置くかを指定します。
| 段階 | 主なCSS | 役割 |
|---|---|---|
| アンカーを作る | anchor-name |
基準要素へ --menu-button のような名前を付ける |
| 関連付ける | position-anchor |
配置する要素が、何を位置の基準にするか決める |
| 位置を決める | position-area / anchor() |
基準の上、下、右などへ置く |
anchor-name の値は、CSSカスタムプロパティと同じように -- で始まる識別子です。配置される側は position: absolute または position: fixed にし、position-anchor でその名前を参照します。
最小例: ボタンの上にツールチップを置く
明示的なアンカー名を使う最小構成は次のようになります。ツールチップの開閉方法は省略し、ここでは配置だけに注目します。
<button class="help-button" aria-describedby="help-tip">ヘルプ</button>
<div id="help-tip" class="tooltip" role="tooltip">入力例を確認できます</div>
.help-button {
anchor-name: --help;
}
.tooltip {
position: fixed;
position-anchor: --help;
position-area: block-start;
margin-block-end: 8px;
}
position-area: block-start は、横書きなら通常アンカーの上側を使います。top のような物理方向もありますが、縦書きや書字方向を考えるなら block-start、inline-end などの論理方向が有用です。
ここで大切なのは、関連付けただけでは位置が決まらないことです。anchor-name と position-anchor は関係を作り、position-area や anchor() が実際の場所を決めます。
position-areaは基準の周囲をグリッドとして選ぶ
position-area は、アンカーの周囲を3×3の区画として考え、配置する要素をどこへ置くか指定するプロパティです。単純なツールチップやメニューなら、top や left を個別に計算するより、指定の意図が読み取りやすくなります。
.above { position-area: block-start; }
.below { position-area: block-end; }
.right { position-area: inline-end; }
.corner { position-area: block-end inline-end; }
CSSの位置計算では、要素を置く基準となる領域を「包含ブロック」と呼びます。position-area は、アンカーと包含ブロックの端から作られる区画を選び、その区画の中に要素を配置します。「ボタンの上」「ボタンの右下」といった意図を、座標値の計算より直接的に表せます。
一方、細かなオフセットや複数アンカーの辺を組み合わせたい場合は、次に説明する anchor() のほうが向いています。
anchor()とanchor-size()で位置と大きさを参照する
anchor() 関数は、アンカーの上端、下端、中央などの位置を長さとして参照します。top や left などの位置指定、論理方向のinsetプロパティ、calc() と組み合わせられます。
.menu {
position: fixed;
position-anchor: --menu-button;
top: calc(anchor(bottom) + 8px);
left: anchor(left);
min-width: anchor-size(width);
}
この例では、メニュー上端をボタン下端から8px離し、左端をそろえ、最小幅をボタン幅に合わせます。anchor-size() はアンカーの幅や高さを参照するため、トリガーボタンと同じ幅の選択メニューなどに使えます。
anchor() は多くのことを表現できますが、単純な上下左右の配置まで複雑な式にする必要はありません。基本位置は position-area、細部だけ anchor() と分けると保守しやすくなります。
画面端ではposition-tryで配置候補を切り替える
Anchor Positioningの実用上の要点が、オーバーフロー時の代替配置です。たとえばツールチップをボタンの上へ置いても、ボタンが画面上端に近ければツールチップが見切れます。
.tooltip {
position: fixed;
position-anchor: --help;
position-area: block-start;
position-try-fallbacks: flip-block;
}
flip-block は、ブロック方向で配置を反転する定義済みの候補です。通常の横書きでは上下方向に当たり、上側に収まらなければ下側への配置を試します。複数の候補はカンマ区切りで順番に指定でき、@position-try で位置や幅を含む独自の候補も定義できます。position-try は、候補と試す順序をまとめて指定するショートハンドです。
ただし、指定した候補の中から必ず画面内に収まる位置が見つかるとは限りません。MDNの説明では、どの候補でもはみ出しを解消できない場合、最初に指定した位置へ戻ります。コンテンツの最大幅、画面端の余白、必要に応じたスクロールも合わせて設計します。
Popover APIと組み合わせると何が簡単になるのか
Popover APIとCSS Anchor Positioningは競合する仕組みではなく、役割が異なります。Popover APIは、Popoverの表示・非表示やtop layerへの移動を扱います。既定の popover="auto" と popover="hint" では、外側をクリックして閉じるlight dismissも利用できます。Anchor Positioningは、そのPopoverをボタンの上・下・左右のどこへ置くかを扱います。
<button popovertarget="account-menu">アカウント</button>
<div id="account-menu" popover>...</div>
#account-menu {
position-area: block-end;
position-try-fallbacks: flip-block;
margin-block-start: 8px;
}
CSSWG仕様とMDNのガイドでは、popovertarget などでPopoverと操作ボタンを関連付けると、暗黙のアンカー関係が作られると説明されています。この場合、明示的な anchor-name と position-anchor を省ける構成があります。
ただし、Popoverを使っただけで、メニューやツールチップとしての意味が自動的に付くわけではありません。表示・非表示、画面上の位置、HTML上の意味、キーボードでの操作方法をそれぞれ確認する必要があります。
CSSだけでアクセシビリティまで完成するわけではない
CSSWG仕様は、Anchor Positioning自体は要素間のアクセシビリティ上の関連付けを作成・削除・変更しないと明記しています。位置が正しく見えていても、操作ボタンと説明内容の関係がスクリーンリーダーへ自動的に伝わるわけではありません。
CSSで置き換えられるのは、主に基準要素の座標測定と表示位置の切り替えです。UI全体の振る舞いまで、常にCSSだけで完成するという意味ではありません。
- ツールチップは、マウスだけでなくキーボードフォーカスでも利用できるか
- メニューなら、矢印キーやEscapeキー、フォーカス移動をどう扱うか
- Popoverを閉じたあと、フォーカスをどこへ戻すか
- 表示内容と操作ボタンの関係が、スクリーンリーダーなどの支援技術へ伝わるか
- 拡大表示や長い翻訳文でも、内容が切れず読めるか
Popover APIは便利な標準動作を提供しますが、popover 属性を付けるだけで任意のメニュー、ダイアログ、ツールチップのアクセシビリティ要件が満たされるわけではありません。HTMLの意味、必要なARIA、フォーカスとキーボード操作をコンポーネントごとに設計します。
繰り返しコンポーネントではanchor-scopeに注意する
同じカードを何十件も並べ、各カードに同じ名前のアンカーとPopoverを置く場合、どのアンカーを選ぶかが問題になります。現行のCSSWG草案とMDNでは、同じ anchor-name を持つ候補が複数あり、アンカーにできる祖先要素がない場合、DOM上で最後の候補が選ばれると説明されています。
anchor-scope は、アンカー名を参照できる範囲を特定のサブツリー内に限定するプロパティです。繰り返しコンポーネントの内側だけで同じ名前を再利用したいときに使います。
.product-card {
anchor-scope: --actions;
}
.product-card__button {
anchor-name: --actions;
}
.product-card__menu {
position: absolute;
position-anchor: --actions;
position-area: block-end;
}
単一のデモでは動いても、一覧へ展開すると複数のPopoverが同じボタンを基準にしてしまう可能性があります。再利用コンポーネントでは、Popover APIによる暗黙の関連付けを使えるか、名前を一意にするか、anchor-scope で参照範囲を限定するかを決めます。この部分もWorking Draftであり、CSSWG草案には再利用例を見直す編集メモが残っているため、対象ブラウザでの動作確認が必要です。
対応状況とフォールバックをどう考えるか
CSS Anchor Positioning Module Level 1は、2026年5月8日付のW3C Working Draftです。Working Draftは作業中の文書であり、将来更新、置換、廃止される可能性があります。一方、MDNでは anchor-name がBaseline 2026のNewly availableとされ、最新ブラウザでの利用範囲は広がっています。ただし古い端末・ブラウザでは動かず、機能の一部は対応レベルが異なると明記されています。
したがって、「2026年なら無条件で使える」でも「実験機能だから使えない」でもありません。対象ユーザーのブラウザ構成と、使うプロパティごとの互換性を確認する段階です。
次の例は、ツールチップがボタンと同じ .trigger-wrap の中にある場合です。非対応ブラウザでは従来の絶対配置を使い、対応ブラウザではAnchor Positioningへ切り替えます。
.trigger-wrap {
position: relative;
width: fit-content;
}
.tooltip {
position: absolute;
inset-block-end: calc(100% + 8px);
inset-inline-start: 50%;
transform: translateX(-50%);
}
@supports (anchor-name: --trigger) {
.trigger { anchor-name: --trigger; }
.tooltip {
position: fixed;
position-anchor: --trigger;
position-area: block-start;
position-try-fallbacks: flip-block;
inset: auto;
transform: none;
}
}
非対応ブラウザで、対応ブラウザとまったく同じ見た目を再現する必要はありません。重要な情報は通常の文書内にも表示する、ツールチップを単純な上固定にする、複雑な製品では実績のある配置ライブラリを残す、といった段階的な導入が現実的です。
実務導入で確認したいチェックポイント
採用時は、見栄えのよいデモだけで判断せず、実際のコンテンツと操作条件で確認します。
- 基準を決める: 何をアンカーとし、暗黙・明示のどちらで関連付けるか。
- 初期位置を決める: 論理方向を使い、通常時に最も自然な場所を選ぶ。
- 崩れやすい条件で試す: 四隅、狭い画面、200%拡大、長文、右から左へ書く言語で確認する。
- 候補を絞る: 必要以上に多くの配置候補を並べず、UIとして自然な順序にする。
- 矢印も追従させる: 位置を反転するなら、吹き出しの矢印方向も更新する。
- 操作を検証する: キーボード、フォーカス、読み上げ、閉じる操作を確認する。
- 非対応時を確認する: 情報や主要操作が失われないフォールバックを用意する。
特に、配置が反転したのに矢印だけ元の方向を指している状態は、見た目だけでなく「どの要素の説明か」を誤解させます。アンカーとの視覚的な関係も、フォールバック状態の一部としてテストします。
まとめ: ツールチップの位置計算をCSSに任せられる
CSS Anchor Positioningが変えるのは、ツールチップやPopoverの存在そのものではなく、その「置き場所」の責任分担です。
anchor-nameとposition-anchorで、どの要素を位置の基準にするか指定するposition-areaで基準の上下左右へ宣言的に置くanchor()とanchor-size()で位置・大きさを参照するposition-try系で画面端の代替配置を試す- Popover APIと組み合わせ、表示・非表示と位置計算をブラウザの標準機能で実装できる
- 仕様はWorking Draftであり、互換性確認とフォールバックはまだ重要
位置の計算をCSSへ移せば、JavaScriptは開閉状態、データ、キーボード操作などに集中できます。ただし、アクセシビリティや非対応環境まで自動的に解決されるわけではありません。まずは、重要な操作を妨げない補助的なツールチップや設定Popoverから段階的に試すのが、2026年時点では堅実な使い方です。
参考文献・ソース
- W3C CSS Working Group — CSS Anchor Positioning Module Level 1 ↗
- MDN Web Docs — CSS anchor positioning ↗
- MDN Web Docs — Using CSS anchor positioning ↗
- MDN Web Docs — Fallback options and conditional hiding for overflow ↗
- MDN Web Docs — anchor-name ↗
- MDN Web Docs — anchor-scope ↗
- MDN Web Docs — Popover API ↗
- WHATWG HTML Standard — The Popover API ↗
記事作成に関する注記
本記事は AI(大規模言語モデル)を編集補助として活用して作成しています。 公開前に編集者が内容を確認していますが、事実誤認・仕様の解釈ミス・最新情報との齟齬が含まれる可能性があります。 重要な判断を行う際は、本文中の一次ソースや公式ドキュメントを必ずご自身でご確認ください。 誤りにお気づきの場合は、お問い合わせフォームよりご連絡いただけると助かります。


