CSSのAnchor Positioningでツールチップを実装する
ツールチップやポップオーバーの位置決め、今までJavaScriptで頑張ってませんでしたか?
「ボタンの上に出したい」「画面端ではみ出さないように」とか、地味にめんどくさいやつです。
CSS Anchor Positioningを使うと、これがCSSだけでできるようになります。
しかも画面端での自動位置調整まで付いてきます。
今回は基本的な使い方から実践的な例まで、まとめて紹介してみます。
▶ サンプルページを見る(ツールチップ・ポップオーバー・バリデーションのデモ)
目次
CSS Anchor Positioningとは
CSS Anchor Positioningは、ある要素(アンカー)を基準にして別の要素を配置できるCSSの仕組みです。
たとえば「このボタンの上にツールチップを出す」みたいなことが、CSSだけで書けます。
核となるプロパティは2つです。
- anchor-name: 基準となる要素に名前をつける
- position-anchor: 配置したい要素から、どのアンカーに紐づけるか指定する
これだけで要素同士が紐づきます。あとは位置を指定するだけです。
これまでのツールチップ実装の課題
従来のツールチップ実装には、だいたいこんな問題がありました。
- JSでの位置計算が必要:
getBoundingClientRect()で座標を取って、top/leftを計算するコードが必要 - 画面端でのはみ出し: ビューポートの端にある要素だとツールチップが見切れる。はみ出し検知も自前で書く必要がある
- スクロール追従: スクロールすると位置がずれる。scroll/resizeイベントを監視して再計算が必要
- ライブラリへの依存: Floating UIやPopper.jsを入れればラクだけど、バンドルサイズが増える
CSS Anchor Positioningなら、これらをブラウザがネイティブに解決してくれます。
基本的な使い方
最小構成を見てみます。3ステップです。
1. アンカーに名前をつける(anchor-name)
基準にしたい要素にanchor-nameを設定します。値はCSS変数と同じく--で始めます。
.anchor-button {
anchor-name: --my-button;
}
2. 配置する要素をアンカーに紐づける(position-anchor)
ツールチップなどの配置したい要素にposition-anchorを設定します。position: absoluteまたはposition: fixedが必要です。
.tooltip {
position: absolute;
position-anchor: --my-button;
}
3. 位置を指定する(position-areaまたはanchor関数)
位置の指定方法は2つあります。
方法A: position-area(シンプル)
アンカーを中心にした3×3のグリッドのどこに配置するか、キーワードで指定します。
.tooltip {
position: absolute;
position-anchor: --my-button;
position-area: top; /* アンカーの上に配置 */
}
使えるキーワードの例: top, bottom, left, right, top left, bottom right, center など。
方法B: anchor()関数(細かく制御)
top, leftなどのインセットプロパティでanchor()関数を使います。
.tooltip {
position: absolute;
position-anchor: --my-button;
/* アンカーの上辺から8px上にずらす */
bottom: calc(anchor(top) + 8px);
/* アンカーの水平中央に合わせる */
left: anchor(center);
translate: -50% 0;
}
anchor()の引数にはtop, bottom, left, right, centerのほか、パーセント値(anchor(50%))も使えます。
実例1: シンプルなツールチップ(ホバーで表示)
まずは一番よくあるパターン。ボタンにホバーしたらツールチップが出る例です。
<div class="tooltip-wrapper">
<button class="anchor-btn">ホバーしてね</button>
<div class="tooltip" role="tooltip">これがツールチップです</div>
</div>
/* アンカーの設定 */
.anchor-btn {
anchor-name: --tooltip-anchor;
}
/* ツールチップ */
.tooltip {
position: absolute;
position-anchor: --tooltip-anchor;
position-area: top;
width: max-content;
margin-bottom: 8px;
background: #333;
color: #fff;
padding: 6px 12px;
border-radius: 4px;
font-size: 14px;
/* 初期状態は非表示 */
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
/* ホバー or キーボードフォーカスで表示 */
.anchor-btn:hover + .tooltip,
.anchor-btn:focus-visible + .tooltip {
opacity: 1;
}
position-area: topでアンカーの上に配置し、margin-bottomで少し隙間を空けています。width: max-contentを入れておくと、テキストが不自然に折り返されるのを防げます。
:focus-visibleも入れておくと、キーボード操作でも表示されるのでアクセシビリティ的にも良いですね。
実例2: ポップオーバー(popover属性との組み合わせ)
HTMLのpopover属性とAnchor Positioningを組み合わせると、JSなしでポップオーバーが作れます。
<button class="info-btn" popovertarget="info-popover">
ℹ️ 詳細
</button>
<div id="info-popover" popover="auto" class="popover-content">
<p>この機能はベータ版です。</p>
<p>フィードバックは<a href="#">こちら</a>からお願いします。</p>
</div>
/* ボタンをアンカーに */
.info-btn {
anchor-name: --info-anchor;
}
/* ポップオーバーの配置 */
.popover-content {
/* popoverのデフォルトinsetをリセット */
inset: auto;
margin: 0;
position-anchor: --info-anchor;
position-area: bottom;
margin-top: 8px;
/* スタイリング */
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
max-width: 300px;
}
popover属性の要素はトップレイヤーに配置されるので、z-indexの問題を気にしなくて済みます。popovertargetでボタンとポップオーバーを紐づけるので、開閉のJSも不要です。
popover="auto"にすると、外側をクリックしたときやEscキーで自動的に閉じてくれます。
注意点として、popover要素はデフォルトでinset: 0とmargin: autoが設定されています。Anchor Positioningで位置を制御するために、これらをリセットしておく必要があります。
実例3: フォームのバリデーションメッセージ
入力フィールドの横にエラーメッセージを表示するパターンです。
<form class="form-example">
<div class="form-group">
<label for="email">メールアドレス</label>
<input
type="email"
id="email"
class="form-input"
required
placeholder="example@mail.com"
/>
<span class="error-msg">有効なメールアドレスを入力してください</span>
</div>
</form>
/* 包含ブロックの設定(absoluteの基準) */
.form-group {
position: relative;
}
/* 入力フィールドをアンカーに */
.form-input {
anchor-name: --email-input;
}
/* エラーメッセージの配置 */
.error-msg {
position: absolute;
position-anchor: --email-input;
position-area: right;
margin-left: 12px;
color: #dc3545;
font-size: 13px;
white-space: nowrap;
/* 初期状態は非表示 */
display: none;
}
/* バリデーション失敗時に表示 */
.form-input:invalid:not(:placeholder-shown) + .error-msg {
display: block;
}
/* 画面が狭いときは下に配置 */
@media (max-width: 640px) {
.error-msg {
position-area: bottom;
margin-left: 0;
margin-top: 4px;
}
}
:invalid:not(:placeholder-shown)で、ユーザーが入力してバリデーションに引っかかったときだけメッセージを表示しています。初期状態では出ません。
メディアクエリで画面幅が狭いときはposition-areaをbottomに変えて、フィールドの下に表示するようにしました。position-areaの値を変えるだけで配置を切り替えられるのが便利ですね。
position-areaとposition-try-fallbacksによる自動位置調整
Anchor Positioningの真骨頂がこの自動位置調整です。
画面端でツールチップがはみ出しそうなとき、自動的に別の位置にフォールバックしてくれます。
flip-blockとflip-inline
一番手軽なのは組み込みのflipキーワードです。
.tooltip {
position: absolute;
position-anchor: --my-anchor;
position-area: top;
/* 上にスペースがなければ下に反転 */
position-try-fallbacks: flip-block;
}
/* 横方向の反転 */
.tooltip-horizontal {
position: absolute;
position-anchor: --my-anchor;
position-area: right;
/* 右にスペースがなければ左に反転 */
position-try-fallbacks: flip-inline;
}
/* 上下左右すべてを候補にする */
.tooltip-full {
position: absolute;
position-anchor: --my-anchor;
position-area: top right;
position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
}
flip-block: ブロック軸(縦方向)で反転。topならbottomへflip-inline: インライン軸(横方向)で反転。rightならleftへflip-block flip-inline: 両方向を同時に反転(スペース区切りで1つのオプションとして指定)
@position-tryでカスタムフォールバック
flipだけでは足りない場合、@position-tryで独自のフォールバック位置を定義できます。
/* カスタムフォールバックの定義 */
@position-try --below {
position-area: bottom;
margin-top: 8px;
margin-bottom: 0;
}
@position-try --left-side {
position-area: left;
margin-right: 8px;
margin-bottom: 0;
}
.tooltip {
position: absolute;
position-anchor: --my-anchor;
position-area: top;
margin-bottom: 8px;
/* 上 → 下 → 左 の順で試す */
position-try-fallbacks: --below, --left-side;
}
ブラウザはまずデフォルトの位置(top)を試して、はみ出す場合は--below、それでもダメなら--left-sideを試します。
flipキーワードとカスタムオプションを混在させることもできます。
.tooltip {
/* flip-blockを先に試して、ダメならカスタム位置 */
position-try-fallbacks: flip-block, --left-side;
}
ブラウザ対応状況(2026年3月時点)
2026年3月時点での対応状況です。
- Chrome / Edge: 125以降で対応(2024年5月〜)
- Safari: 26以降で対応(2025年9月〜)
- Firefox: 145以降で対応(2026年1月〜)
2026年1月にFirefoxが対応したことで、主要ブラウザすべてで使えるようになりました。Interop 2026の対象機能にも含まれていて、ブラウザ間の互換性も改善が進んでいます。
ただし古いバージョンのブラウザをサポートする必要がある場合は、フォールバックを用意しておくと安心です。
@supportsでのフォールバック
@supportsで機能検出して、非対応ブラウザ向けのフォールバックを書けます。
/* フォールバック: Anchor Positioning非対応ブラウザ向け */
.tooltip-wrapper {
position: relative;
}
.tooltip {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
margin-bottom: 8px;
}
/* Anchor Positioningが使える場合は上書き */
@supports (anchor-name: --x) {
.tooltip-wrapper {
position: static;
}
.tooltip {
position-anchor: --tooltip-anchor;
position-area: top;
bottom: auto;
left: auto;
transform: none;
position-try-fallbacks: flip-block;
}
}
ポイントは、まず従来の方法(position: relativeの親 + position: absoluteの子)でベースのスタイルを書いておき、@supportsの中でAnchor Positioning版に上書きするところです。
これなら非対応ブラウザでもツールチップが壊れることはありません。位置の自動調整は効きませんが、基本的な表示は保たれます。
OddBirdが提供しているポリフィルを使う手もあります。
<script src="https://unpkg.com/@oddbird/css-anchor-positioning/dist/css-anchor-positioning-fn.js"></script>
<script>
if (!CSS.supports('anchor-name: --x')) {
window.applyAnchorPositioning();
}
</script>
ただし、主要ブラウザの最新版はすべて対応済みなので、ポリフィルが必要なケースは減ってきています。
JSライブラリ(Floating UI等)との使い分け
「Floating UIを使ってるけど、Anchor Positioningに置き換えるべき?」という疑問が出ると思います。
ざっくりまとめるとこんな感じです。
- CSS Anchor Positioningが向いているケース
- シンプルなツールチップ、ポップオーバー
- JSの依存を減らしたい
- パフォーマンスを重視したい(ブラウザネイティブなので高速)
- 静的な要素同士の紐づけ
- Floating UIが向いているケース
- カーソル位置に追従するツールチップ(仮想要素のアンカー)
- 複雑なインタラクション(ドラッグ&ドロップとの連携など)
- 古いブラウザのサポートが必須
- React/Vueなどのフレームワークとの統合が必要
個人的には、新規プロジェクトでシンプルなツールチップやドロップダウンを作るなら、まずCSS Anchor Positioningで試してみるのが良いかなと思っています。JSのバンドルサイズが減るし、スクロール時のパフォーマンスもブラウザに任せられます。
複雑なケースや古いブラウザ対応が必要なら、Floating UIの出番ですね。両方知っておいて使い分けるのがベストだと思います。
まとめ
CSS Anchor Positioningを使うと、今までJSで書いていたツールチップやポップオーバーの位置決めがCSSだけでできるようになります。
anchor-nameとposition-anchorで要素同士を紐づけるposition-areaやanchor()関数で位置を指定position-try-fallbacksで画面端の自動位置調整popover属性と組み合わせるとJS完全不要のポップオーバーが作れる- 2026年3月時点で主要ブラウザすべてに対応済み
ブラウザのネイティブ機能なのでパフォーマンスも良く、コード量もぐっと減ります。
ツールチップの位置計算をJSで頑張っていた頃と比べると、めちゃくちゃ楽になりました。
今回は以上です!