1. ホーム
  2. CSS

【CSS】アンカーポジショニングの使い方|anchor-name・position-area でツールチップを要素に紐づける方法

Share

ボタンにマウスを乗せたときのツールチップや、クリックで開くドロップダウンメニューは、「どの要素の近くに出すか」が決まっているパーツです。これまではこうした配置に JavaScript で座標を計算するライブラリを使うのが一般的でしたが、CSS のアンカーポジショニングを使うと、要素同士の紐づけから配置、画面端での反転までを CSS だけで書けるようになります。この記事では anchor-name・position-anchor・position-area・anchor() 関数・position-try-fallbacks の使い方を、動かせるデモつきで解説します。

アンカーポジショニングで何ができるのか

position: absolute; で要素を配置するとき、基準になるのは「position が指定された一番近い祖先要素」(包含ブロック)です。ツールチップをボタンの真上に置きたければ、ボタンとツールチップを共通の親で囲み、親に position: relative; を付けて……というように、HTML の構造を配置の都合に合わせる必要がありました。親に overflow: hidden; が付いていればツールチップは切れてしまいますし、ポップオーバーのように最前面(トップレイヤー)に表示される要素は、そもそもボタンの位置を CSS から参照する手段がありませんでした。

アンカーポジショニングは、基準にしたい要素(アンカー)に名前を付け、配置したい要素からその名前を指定する仕組みです。HTML 上の親子関係とは関係なく、名前でつながった要素の上下左右や角に、配置したい要素を置けます。さらに、下に表示すると画面からはみ出す場合は上に出す、といった代替位置もあわせて指定できます。

この記事で扱うプロパティと関数は次のとおりです。

プロパティ・関数役割指定する要素
anchor-name要素をアンカーとして登録し、名前を付けるアンカー
position-anchorどのアンカーに紐づけるかを名前で指定する配置する要素
position-areaアンカーの周囲 3×3 のマスのどこに置くかを指定する配置する要素
anchor()アンカーの辺の位置を top や left の値として使う配置する要素
position-try-fallbacksはみ出すときに試す代わりの位置を指定する配置する要素

基本の使い方:アンカーに名前を付けて紐づける

最小の構成は3ステップです。まずアンカーにしたい要素に anchor-name で名前を付けます。名前は --save-btn のように、CSS カスタムプロパティと同じく -- から始まる形式(dashed-ident)で書きます。

次に、配置したい要素を position: absolute; か position: fixed; にし、position-anchor で同じ名前を指定します。最後に position-area などで、アンカーのどこに置くかを決めます。

style.css
/* 1. アンカーに名前を付ける */
.btn {
  anchor-name: --save-btn;
}

.tooltip {
  /* 2. 絶対配置にして、アンカーの名前を指定する */
  position: absolute;
  position-anchor: --save-btn;

  /* 3. アンカーの真上に置く */
  position-area: top;
}

これを使ってツールチップを作ったのが次のデモです。ボタンにマウスを乗せる(またはキーボードでフォーカスする)と、ボタンの真上にツールチップが現れます。ツールチップの HTML はボタンの子要素ではなく隣に置いてあるだけで、親要素に position: relative; も付けていない点に注目してください。

<div class="stage">
  <button class="btn" type="button">保存する</button>
  <div class="tooltip">変更内容をサーバーに保存します</div>
</div>
body {
  margin: 16px;
  font-family: sans-serif;
  color: #333;
}

/* 上にツールチップが出る余白をとる */
.stage {
  padding: 64px 0 24px;
  text-align: center;
}

.btn {
  /* 1. このボタンをアンカーとして登録する */
  anchor-name: --save-btn;
  padding: 8px 20px;
  border: none;
  border-radius: 6px;
  background: #007bff;
  color: #fff;
  font-size: 14px;
  cursor: pointer;
}

.tooltip {
  /* 2. 絶対配置にして、紐づけるアンカーを指定する */
  position: absolute;
  position-anchor: --save-btn;
  /* 3. アンカーの真上に置く */
  position-area: top;
  margin-bottom: 8px;
  padding: 6px 10px;
  border-radius: 4px;
  background: #333;
  color: #fff;
  font-size: 12px;
  white-space: nowrap;
  /* ふだんは隠しておく */
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}

/* ホバー中・フォーカス中だけ表示する */
.btn:hover + .tooltip,
.btn:focus-visible + .tooltip {
  opacity: 1;
}
Preview

position-area: top; と書くだけで、ツールチップは自動的にボタンの左右中央にそろいます。ボタンとの間に隙間を空けたいときは、margin-bottom のようにアンカーに面した側のマージンを指定します。

position-area でアンカーの周囲に配置する

position-area は、アンカーを中央のマスとする 3×3 のグリッドを思い浮かべると理解しやすいプロパティです。縦方向は top / center / bottom、横方向は left / center / right の行と列があり、そのどこに置くかをキーワードで指定します。

指定例配置される場所
topアンカーの上。横方向は3列すべてにまたがり、アンカーの中央にそろう
bottomアンカーの下。横方向の扱いは top と同じ
left / rightアンカーの左 / 右。縦方向はアンカーの中央にそろう
top rightアンカーの右上の角のマス
bottom span-rightアンカーの下で、中央と右の2列にまたがる(左端がアンカーの左端にそろう)
top span-leftアンカーの上で、中央と左の2列にまたがる(右端がアンカーの右端にそろう)
centerアンカーと重なる中央のマス

span- の付いたキーワードは「中央の列と、指定した側の列の2マスにまたがる」という意味です。ドロップダウンメニューのように、ボタンの左端からそろえて右へ広げたいときは bottom span-right がちょうど合います。行と列を1つしか書かなかった場合、もう一方の軸は3マスすべてにまたがる扱い(top なら top span-all)になります。

ここでは物理的な方向(上下左右)のキーワードで説明しましたが、block-start / inline-end のような論理方向のキーワードも用意されています。縦書きや右から左に書く言語に対応させたい場合は、そちらを使うと書字方向に合わせて配置が切り替わります。

anchor() 関数で辺を基準に細かく配置する

position-area はマス単位でおおまかに置く方法でした。「アンカーの右上の角に、バッジの中心をぴったり合わせたい」のように、もっと細かく位置を決めたいときは anchor() 関数を使います。anchor() はアンカーの指定した辺の位置を返す関数で、top / right / bottom / left などの値として使います。

style.css
.badge {
  position: absolute;
  position-anchor: --bell;

  /* 自分の上端を、アンカーの上端の位置に合わせる */
  top: anchor(top);
  /* 自分の左端を、アンカーの右端の位置に合わせる */
  left: anchor(right);
}

読み方は「自分の top を、アンカーの top と同じ位置にする」です。左辺のプロパティが自分のどの辺か、anchor() の中のキーワードがアンカーのどの辺かを表しています。主に使うキーワードは次のとおりです。

キーワード返す位置
top / bottomアンカーの上端 / 下端
left / rightアンカーの左端 / 右端
centerアンカーのその軸での中央
start / end書字方向に沿った論理的な始まり / 終わりの辺
50% などの割合始まりの辺から指定した割合の位置(0% が始まり、100% が終わり)

anchor() の結果は長さとして扱われるので、calc() の中で足し引きもできます。次のデモでは、ベルのアイコンの右上の角に通知数のバッジを、メールのアイコンの下にラベルを配置しています。バッジは translate: -50% -50%; で自分の大きさの半分だけ戻すことで、バッジの中心が角に来るようにしています。

<div class="stage">
  <button class="icon" type="button" aria-label="お知らせ">🔔</button>
  <span class="badge">3</span>

  <button class="icon icon--mail" type="button" aria-label="メッセージ">✉️</button>
  <span class="label">新着メッセージ</span>
</div>
body {
  margin: 16px;
  font-family: sans-serif;
  color: #333;
}

.stage {
  display: flex;
  gap: 64px;
  padding: 24px 24px 48px;
}

.icon {
  anchor-name: --bell;
  width: 48px;
  height: 48px;
  border: 1px solid #ddd;
  border-radius: 8px;
  background: #fff;
  font-size: 22px;
}

.icon--mail {
  anchor-name: --mail;
}

/* アンカーの右上の角にバッジの中心を合わせる */
.badge {
  position: absolute;
  position-anchor: --bell;
  top: anchor(top);    /* バッジの上端 = アンカーの上端 */
  left: anchor(right); /* バッジの左端 = アンカーの右端 */
  translate: -50% -50%; /* 自分の大きさの半分だけ戻して中心を角に置く */
  min-width: 20px;
  padding: 2px 6px;
  border-radius: 999px;
  background: #e53935;
  color: #fff;
  font-size: 12px;
  text-align: center;
  box-sizing: border-box;
}

/* アンカーの下端から 6px 下、左右中央に置く */
.label {
  position: absolute;
  position-anchor: --mail;
  top: calc(anchor(bottom) + 6px);
  left: anchor(center);
  translate: -50% 0;
  font-size: 12px;
  white-space: nowrap;
}
Preview

anchor() の第1引数にアンカー名を書くと、position-anchor で指定したものとは別のアンカーを参照できます。たとえば left: anchor(--start right); と right: anchor(--end left); を組み合わせれば、2つの要素のあいだを埋める要素も作れます。ただ、ふだんは position-anchor で紐づけて名前を省略する書き方で十分です。

position-try-fallbacks で画面端では反対側に出す

ドロップダウンメニューをボタンの下に出す設計にしていても、ボタンが画面の下端近くにあるとメニューは画面からはみ出してしまいます。こうしたときに「入らないならこの位置を試してほしい」という代替案を指定するのが position-try-fallbacks です。ブラウザーは最初の位置ではみ出すと判断すると、指定した候補を順に試し、収まる位置に切り替えます。

候補として最も手軽なのが、元の位置を反転させるキーワードです。

値試す位置
flip-blockブロック方向(横書きなら上下)に反転した位置
flip-inlineインライン方向(横書きなら左右)に反転した位置
flip-startブロック方向とインライン方向を入れ替えた位置(例:下に出すものを右に出す)
flip-block flip-inline上下と左右の両方を反転した位置(空白区切りで組み合わせる)
top などの position-area の値その position-area を指定した位置
--名前@position-try で定義した独自の候補

候補は flip-block, flip-inline のようにカンマで区切って複数並べられ、左から順に試されます。次のデモは、ポップオーバー(popover 属性)で作ったメニューをボタンの下に出し、入らないときは flip-block で上に出すようにしたものです。プレビュー内をスクロールして、ボタンを下端付近に移動させてから開いてみてください。

<p class="note">プレビューをスクロールしてボタンを下端に近づけてから開くと、メニューが上側に出ます。</p>
<div class="spacer"></div>

<button class="menu-btn" type="button" popovertarget="menu">メニューを開く</button>
<div class="menu" id="menu" popover>
  <a href="#">プロフィール</a>
  <a href="#">設定</a>
  <a href="#">ログアウト</a>
</div>

<div class="spacer"></div>
body {
  margin: 16px;
  font-family: sans-serif;
  color: #333;
}

.note {
  margin: 0;
  font-size: 13px;
}

/* スクロールできるように上下に余白をとる */
.spacer {
  height: 360px;
}

.menu-btn {
  anchor-name: --menu-btn;
  padding: 8px 16px;
  border: 1px solid #007bff;
  border-radius: 6px;
  background: #fff;
  color: #007bff;
  font-size: 14px;
  cursor: pointer;
}

.menu {
  position-anchor: --menu-btn;
  /* ポップオーバーの既定スタイル(中央寄せ)を打ち消す */
  margin: 0;
  inset: auto;
  /* ボタンの下、左端をそろえて右へ広げる */
  position-area: bottom span-right;
  margin-block: 6px;
  /* 下に収まらないときは上下を反転する */
  position-try-fallbacks: flip-block;
  padding: 4px 0;
  border: 1px solid #ddd;
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

.menu a {
  display: block;
  padding: 8px 20px;
  color: #333;
  font-size: 14px;
  text-decoration: none;
}

.menu a:hover {
  background: #f0f6ff;
}
Preview

ポップオーバーはトップレイヤーに表示されるため、HTML 上の位置に関係なく最前面に出ます。それでもボタンの位置に追従できるのは、アンカーポジショニングで名前を介して紐づけているからです。なお MDN では、popovertarget 属性でボタンとポップオーバーを関連付けた場合、両者のあいだに暗黙のアンカー参照が作られると説明されています。このデモでは仕組みが分かりやすいよう、anchor-name と position-anchor を明示的に書いています。

margin-block: 6px; で上下両方にマージンを付けているのは、上下どちらに反転してもボタンとのあいだに隙間ができるようにするためです。

@position-try で独自の候補を定義する

反転だけでは足りず、「下に入らなければ右に出し、そのときは隙間を左側に取りたい」のように、候補ごとにマージンなどを変えたい場合は @position-try ルールで候補を定義します。名前は -- から始め、position-try-fallbacks にその名前を書きます。

style.css
/* 右側に出す候補 */
@position-try --to-right {
  position-area: right;
  margin: 0 0 0 8px;
}

.tooltip {
  position: absolute;
  position-anchor: --save-btn;
  position-area: bottom;
  margin: 8px 0 0;

  /* 下 → 上(反転)→ 右 の順に試す */
  position-try-fallbacks: flip-block, --to-right;
}

@position-try の中に書けるのは、position-area や top などの位置指定、マージン、幅や高さ、配置(align・justify 系)といった、配置に関わるプロパティに限られます。色や余白(padding)のような見た目のプロパティは書いても反映されません。

対応ブラウザーの状況

MDN では、anchor-name・position-area・position-try-fallbacks などのアンカーポジショニングの各機能が「Baseline 2026(Newly available)」と表示されています。2026年1月以降、主要ブラウザーの最新版でそろって使えるようになった、という意味です。一方で「新しく使えるようになった」段階なので、更新されていない古いブラウザーでは動きません。また MDN には「一部の機能はサポート状況に差がある」という注記もあるため、細かな値まで使う場合はブラウザー互換性表で確認してください。

対応していないブラウザーでは、anchor-name や position-area は無視され、ツールチップは包含ブロックを基準にしたふつうの絶対配置になります。思わぬ位置に表示されるのを避けたい場合は、@supports で対応ブラウザーにだけアンカーポジショニングを適用し、それ以外には従来の配置を残しておくと安全です。

style.css
/* 従来の方法:親を基準にボタンの上へ置く */
.tooltip-wrap {
  position: relative;
}

.tooltip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  translate: -50% 0;
}

/* アンカーポジショニングに対応していれば置き換える */
@supports (anchor-name: --a) {
  .tooltip-wrap {
    position: static;
  }

  .btn {
    anchor-name: --save-btn;
  }

  .tooltip {
    position-anchor: --save-btn;
    position-area: top;
    bottom: auto;
    left: auto;
    translate: none;
    margin-bottom: 8px;
  }
}

ツールチップがアンカーの位置に出ないときの原因

書いたつもりなのに画面の左上に出てしまう、別のボタンの横に出てしまう、というときは、次の点を順に確認してみてください。

配置する要素が position: absolute / fixed になっていない

position-anchor や position-area は、position が absolute か fixed の要素にしか効きません。position: relative; や指定なしのままだと、アンカーの名前を書いても何も起きません。ポップオーバーは既定で position: fixed; になっているので追加の指定は不要ですが、ふつうの div で作るツールチップでは忘れやすいポイントです。

同じ anchor-name が複数の要素に付いている

一覧の各行に「詳細」ボタンがあり、共通のクラスで anchor-name: --detail-btn; を付けた、というケースです。同じ名前のアンカーが複数あると、配置する要素はソース順で最後にあるアンカーに紐づきます。そのため、どの行のツールチップも最後の行のボタンの横に集まってしまいます。

ボタンとツールチップの組が複数あるときは、組ごとに別の名前を付ける必要があります。テンプレート側で連番を振り、インラインの style 属性で名前を渡すのが確実です。

index.html
<button class="btn" style="anchor-name: --detail-1;">詳細</button>
<div class="tooltip" style="position-anchor: --detail-1;">1件目の詳細</div>

<button class="btn" style="anchor-name: --detail-2;">詳細</button>
<div class="tooltip" style="position-anchor: --detail-2;">2件目の詳細</div>

アンカーが display: none などで非表示になっている

アンカーになる要素が display: none; や visibility: hidden; で隠れている場合や、content-visibility: hidden; が付いた要素の中にあって描画がスキップされている場合は、紐づけができません。スマートフォン表示でだけボタンを隠している、といったレスポンシブの切り替えで起きやすいので、表示が崩れる画面幅でアンカーが見えているかを開発者ツールで確認してください。

ポップオーバーが画面の中央に出てしまう

popover 属性を付けた要素には、ブラウザーの既定スタイルとして inset: 0; と margin: auto; が当たっており、画面の中央に表示されるようになっています。この既定値が残っていると position-area を指定してもアンカーの横に移動しません。デモのように margin: 0; と inset: auto; で打ち消してから、必要なマージンを指定し直しましょう。

anchor() を top や left 以外のプロパティで使っている

anchor() 関数が使えるのは、top / right / bottom / left や inset などの位置を指定するプロパティの中だけです。margin-left: anchor(right); や translate の中に書いても無効になります。位置をずらしたいときは、left: calc(anchor(right) + 8px); のように位置指定プロパティの側で計算してください。

まとめ

CSS のアンカーポジショニングは、基準にしたい要素に anchor-name で名前を付け、position: absolute; または fixed; の要素から position-anchor でその名前を指定して紐づける仕組みです。配置はアンカーを中心とした 3×3 のマスで指定する position-area が手軽で、角に合わせるなど細かく決めたいときは anchor() 関数を top や left の値に使います。画面端ではみ出すときの代替位置は position-try-fallbacks に flip-block などで指定でき、独自の候補は @position-try で定義できます。MDN では Baseline 2026 の新しい機能なので、古いブラウザーも対象にする場合は @supports で従来の配置を残しておくと安心です。

参考ページ