このシリーズでは、CSS による絶対配置のレイアウトの自由度を高め、より柔軟かつ堅牢な方法で実装することが可能になる、Anchor Positioning について説明していきます。

今回は、Anchor Positioning の基本的な機能を説明する基礎編です。

本記事で紹介する、Anchor Positioning の機能は、W3C の仕様では「CSS Anchor Positioning Module Level 1」に属しており、草案(Working Draft)段階のため、今後、実装方法や機能に変更が発生する可能性があります。

Safari 26 以降(2025 年 9 月 15 日)、Firefox 147 以降(2026 年 1 月 13 日)でサポートされ、主要なブラウザにおいて基本的な機能がサポートされましたが1、まだブラウザ間で挙動が安定しているとは言い難く、ブラウザによってはサポートされていない機能も存在するため注意が必要です2

要素を絶対配置(position: absolute)で指定することで、通常フローから外れた自由度の高い配置が可能になります。ウェブデザインにおいては欠かせないスタイルの 1 つです。

このとき、ほとんどの場合において、絶対配置の基準となる要素を祖先要素として指定する必要があります。HTML 上では、基準となる要素の内側に絶対配置の要素を配置します。

基準となる要素の内側に絶対配置の要素を配置する例
<!-- HTML -->
<div class="avatar">
  <img src="..." alt="...">
  <p class="hello">Hello!</p>
</div>

<!-- CSS -->
<style>
.avatar {
  position: relative;
}
.hello {
  position: absolute;
}
</style>

一方で、すでに基準となる要素が存在している場合、それより外側に絶対配置の起点を指定することができなくなります。上記のコードであれば、.hello.avatar よりも外側の要素を基準とすることができません。

このように、基準となる要素と絶対配置の要素を子孫関係にする必要があるため、見た目(CSS)のために構造(HTML)が制約されます。

Anchor Positioning では、基準となる要素との結びつきを CSS だけで定義することができるため、この HTML の制約から解放されます。

また、従来の方法では、配置する要素の位置を物理的な値(px%)で指定するため、要素のサイズが変わると表示が崩れてしまったり、ビューポートサイズやスクロール位置によって要素が隠れてしまったりと、変化に柔軟に対応する機能が欠けていました。

Anchor Positioning は、これらの課題にも対応できます。実際に見ていきましょう。

まずは、anchor-name プロパティで基準となる要素(アンカー要素)を指定します。アンカー名はカスタムプロパティと同様に、2 つのハイフン --<dashed-ident>)で始めます。

anchor-name プロパティの例
<!-- HTML -->
<div class="avatar">
  <img src="..." alt="...">
</div>

<!-- CSS -->
<style>
.avatar {
  anchor-name: --hello; 
}
</style>

次に、配置する要素を指定します。position: absolute もしくは position: fixed を指定し、position-anchor プロパティで、アンカー名を指定します。

本記事では、アンカー要素に結びつけて配置する要素を「配置要素」と呼びます。

anchor-name プロパティの例
<!-- HTML -->
<div class="avatar">
  <img src="..." alt="...">
</div>
<p class="hello">Hello!</p>

<!-- CSS -->
<style>
.avatar {
  anchor-name: --avatar;
}
.hello {
  position: absolute; 
  position-anchor: --avatar; 
}
</style>

これで、アンカー要素と配置要素が結びつきました。ここで注目するポイントとしては、各要素が子孫関係にないことです。このように、HTML 構造に依存せずに、CSS 側でアンカーと結びつけることができます。

以下のデモでは、上記のコードをベースに、要素の位置調整やスタイルを追加しました。

Live Demo
アンカー要素

Hello!

アンカーは、anchor-name プロパティによって明示的にアンカー名を指定する方法とは別に、Popover API や <select> 要素のカスタマイズのように、暗黙的にアンカーの機能を持っている場合があります。

以下は、Popover API の例です。ボタンを選択するたびに、メッセージが表示・非表示されます。このとき、popovertarget 属性を指定した要素が暗黙的なアンカー要素で、popover 属性を指定した要素と結びつきます。

Popover API の例
<button type="button" popovertarget="hello" class="btn">
  Greeting
</button>
<p id="hello" popover>Hello!</p>
Live Demo

Hello!

後述する position-area プロパティや anchor() 関数では、配置要素の位置を変更することができますが、この暗黙的なアンカーに対しても同様に使用できます。

アクセシビリティの確保

見出し「アクセシビリティの確保」

ここまで見てきたように、Anchor Positioning を用いることで、従来の絶対配置の課題であった、HTML の制約から解放されます。

しかし、暗黙的なアンカーでない限り、アンカー要素と配置要素には、HTML 上は何の意味づけ(セマンティクス)も与えられません。

そのため、可能な場合には暗黙的なアンカーを使用し3、それ以外の場合には、読み上げ順やフォーカス順序に気を配り、必要に応じて aria-details 属性や aria-describedby 属性など、WAI-ARIA の機能を使用して、アクセシビリティを確保する必要があるでしょう。

配置要素の位置を指定する方法は、position-area プロパティと、anchor() 関数の 2 つに大きく分類できます。

1. position-area プロパティ

見出し「1. position-area プロパティ」

position-area プロパティを使用する方法では、アンカー要素を中心とした 3×3 で構成されたグリッド上の、どのエリアに配置するか指定します。仕様書を読むと、その選択肢の多さに圧倒されてしまうのですが、実例を見ると理解が早いです。

以下は、中央にアンカー要素を配置したデモです。セレクトメニューから position-area プロパティの値を選択して、その変化を確認できます。

このデモは Anchor position tool を参考に作成しました。

Live Demo

Anchor

position-area のキーワードは、半角スペースで区切って 2 つ指定できます。原則としては、1 番目が垂直方向(縦方向)、2 番目が水平方向(横方向)です。

また、キーワードには、topright のような物理値と、block-startinline-end のような論理値があります。論理値の場合には書字方向に応じて向きが変わります。

なお、block-start inline-end のような論理値は、start end と省略できます。上記のデモでは、すべて省略した形にしています。

キーワードは 1 つのみ指定することもできます。たとえば、center であれば center centerstart であれば start start と同じ意味になります。block-start のように繰り返しできないキーワードを単一で指定した場合には、span-all で補完されます。

キーワードを 1 つだけ指定した例
.foo {
  position-area: center;      /* = center center */
}
.bar {
  position-area: block-start; /* = block-start span-all */
}
.baz {
  position-area: inline-end;  /* = span-all inline-end */
}

接頭時に span- が付くものは、複数の行・列に対して配置が可能になります。span-all では、すべての行・列に対して配置されます。

上記のデモでは、論理値・物理値でそれぞれ 27 パターンありますが、これ以外にも、書字方向に関連した self-x-y- といった接頭辞が付くキーワードがあります。ここでは説明をシンプルにするために割愛しましたが、興味があれば W3C の仕様などを確認してください。

この position-area を基準にして、さらに inset- プロパティなどを使用して位置を調整することも可能ですが、細かな位置調整は次に紹介する anchor() 関数が適しています。

anchor() 関数を使用する方法では、inset-topleft といったプロパティに対して、アンカーの位置を指定します。

position-area プロパティとの大きな違いとしては、以下が挙げられます。

  • anchor(25%) のように、パーセント値による相対指定ができる
  • calc()min()max() といった CSS の数学関数が使用できる
  • anchor() に指定するアンカー要素は同一でなくてもよい(複数ポイント指定可能)
  • position-area は基本アニメーション不可だが4anchor() は可能

先ほどと打って変わって、配置要素の側面とアンカー要素の側面の 2 つの組み合わせで考える必要があるためコツがいるのですが、その分、柔軟な指定が可能になります。

Live Demo

Anchor

このように、配置要素のどの側面を、アンカー要素のどの側面に設置させるかの組み合わせで考えます。たとえば、書字方向にもよりますが、配置要素の上辺をアンカー要素の下辺に設置させるには、inline-block-start: anchor(end) と指定します。

なお、配置要素をアンカー要素の中央に配置するには、justify-selfalign-self といったプロパティに対して、anchor-center という値を指定します。

anchor-center を指定した例
.anchor {
  anchor-name: --anchor;
}
.justify-center {
  position: absolute;
  position-anchor: --anchor;
  justify-self: anchor-center; 
}
.align-center {
  position: absolute;
  position-anchor: --anchor;
  align-self: anchor-center; 
}

以下のデモでは、チェックボックスの操作で justify-self: anchor-centeralign-self: anchor-center の挙動を確認できます。

Live Demo

Anchor

前述したように、anchor() 関数には CSS の数学関数が使用できるので、アンカー要素からの距離をまとめて指定することができます。

anchor() に calc() を使用した例
.input {
  anchor-name: --input;
}
.error-message {
  position: absolute;
  position-anchor: --input;
  /* 配置要素の上辺をアンカー要素の下辺から 8px 距離を取る */
  inset-block-start: calc(anchor(end) + 8px); 
  inset-inline-end: anchor(end);
}

複数のアンカー要素との結合

見出し「複数のアンカー要素との結合」

anchor() 関数にアンカー名を指定することで、position-anchor プロパティを使用したときと同じように、アンカー要素と配置要素を結びつけることができます。

anchor() にアンカー名を指定した例
.a {
  anchor-name: --a;
}
.elem {
  position: absolute;
  inset-inline-start: anchor(--a end); 
  inset-inline-end: anchor(--a start); 
}

また、anchor() 関数は、プロパティごとに異なるアンカー名を指定できます。以下の例では、inset-inline-startinset-inline-end で、別のアンカー名を指定しています。

複数のアンカー要素と結びつける例
.a {
  anchor-name: --a;
}
.b {
  anchor-name: --b;
}
.elem {
  position: absolute;
  inset-inline-start: anchor(--a end); 
  inset-inline-end: anchor(--b start); 
}

この手法は、スケジュールの作成で使用するガントチャートやタイムテーブルといったように、始まりと終わりの範囲を示すアイテムを配置するときに活用できそうです。

以下はタイムテーブルのデモです。

Live Demo

Research Stage

Design Stage

Dev Stage

10:00

10:30

11:00

11:30

12:00

12:30

13:00

13:30

14:00

14:30

15:00

[10:00–11:00]AEIOU

[11:00–12:30]Contextual Inquiry

[12:00–13:00]Horror Vacui

[13:00–14:30]Ockhams Razor

[13:30–15:00]Progressive Enhancement

このデモでは、display: grid でタイムテーブルの枠組みを作成し、anchor() 関数で要素を配置しています。

タイムテーブルの HTML コードの抜粋
<!-- アンカー要素(水平軸) -->
<p style="anchor-name: --stage-research;">Research Stage</p>
<p style="anchor-name: --stage-design;">Design Stage</p>
<p style="anchor-name: --stage-dev;">Dev Stage</p>

<!-- アンカー要素(垂直軸) -->
<p style="anchor-name: --time-1300;">13:00</p>
<p style="anchor-name: --time-1330;">13:30</p>
<p style="anchor-name: --time-1400;">14:00</p>
<p style="anchor-name: --time-1430;">14:30</p>

<!-- 配置要素 -->
<p
  style="
    inset-inline-start: anchor(--stage-design start);
    inset-inline-end: anchor(--stage-design end);
    inset-block-start: anchor(--time-1300 start);
    inset-block-end: calc(anchor(--time-1430 start) + 2px);
  "
>
  <span>[13:00&ndash;14:30]</span>
  <span>Ockhams Razor</span>
</p>

このように、縦横の両軸でそれぞれ、開始位置と終了位置をアンカー名で指定することで、複雑な配置が可能になります。従来の物理的な値(px%)で指定する方法と比較して、変化に強くロジカルな実装だといえるでしょう。

ページ内に複数のアンカー要素が存在し、anchor-name の値が重複する場合には、一番最後に出現する要素が対象となります。そのため、特にコンポーネントのように、繰り返し使用する要素が出現したときに問題になります。

重複するアンカー要素が存在する例
<!-- HTML -->
<div class="item">
  <div class="avatar">
    <img src="..." alt="...">
  </div>
  <p class="hello">Foo!</p>
</div>

<div class="item">
  <div class="avatar">
    <img src="..." alt="...">
  </div>
  <p class="hello">Bar!</p>
</div>

<div class="item">
  <div class="avatar">
    <img src="..." alt="...">
  </div>
  <p class="hello">Baz!</p>
</div>

<!-- CSS -->
<style>
.avatar {
  anchor-name: --avatar;
}
.hello {
  position: absolute;
  position-anchor: --avatar;
}
</style>

この場合、一番最後のアンカー要素にすべての配置要素が結びついてしまいます。

Live Demo
アンカー要素

Foo!

アンカー要素

Bar!

アンカー要素

Baz!

この問題を解消するには、anchor-scope プロパティを使用してコンポーネント単位でスコープを定義します。

anchor-scope プロパティの例
.item {
  anchor-scope: all; 
}
.avatar {
  anchor-name: --avatar;
}
.hello {
  position: absolute;
  position-anchor: --avatar;
}

これで、アンカーのスコープをコンポーネント(.item)に閉じ込めることができました。

Live Demo
アンカー要素

Foo!

アンカー要素

Bar!

アンカー要素

Baz!

なお、anchor-scope: all を指定した場合には、すべてのアンカー名が対象になりますが、anchor-scope: --avatar のように、スコープの対象を明示することもできます。また、anchor-scope: --foo, --bar のように、カンマで区切って複数のアンカー名を指定することも可能です。

アンカーのサイズを使用する

見出し「アンカーのサイズを使用する」

anchor-size() 関数を使用して、アンカー要素のサイズを取得できます。論理値のキーワード inlineblock、もしくは物理値のキーワード widthheight などを指定します。

anchor-size() にキーワードを指定した例
.anchor {
  anchor-name: --base;
  inline-size: 400px;
  block-size: 80px;
}
.foo {
  position: absolute;
  position-anchor: --base;
  inset-block-start: anchor-size(block);   /* 80px */
  inset-inline-start: anchor-size(inline); /* 400px */
}
.bar {
  position: absolute;
  position-anchor: --base;
  inset-block-start: calc(anchor-size(block) / 2);   /* 40px */
  inset-inline-start: calc(anchor-size(inline) / 2); /* 200px */
}

キーワードを省略した場合には、プロパティと同じ値になります。たとえば、inline-size: anchor-size() であれば、inline-size: anchor-size(inline) と同じです。

また、anchor() 関数と同様に、anchor-size() 関数にアンカー名を指定することでサイズを取得できます。このとき、position-anchor プロパティを指定しなければ、アンカー要素と結合することなく、サイズのみを取得することができるようです。

ただし、要素に position: absoluteposition: fixed が指定されている必要があります。

anchor-size() にアンカー名を指定した例
.base {
  anchor-name: --base;
  inline-size: 400px;
  block-size: 80px;
}
.foo {
  position: absolute;
  inset-block-start: anchor-size(--base block);   /* 80px */
  inset-inline-start: anchor-size(--base inline); /* 400px */
}
.bar {
  position: absolute;
  inset-block-start: calc(anchor-size(--base block) / 2);   /* 40px */
  inset-inline-start: calc(anchor-size(--base inline) / 2); /* 200px */
}

オーバーフロー時のフォールバックを指定する

見出し「オーバーフロー時のフォールバックを指定する」

Anchor Positioning では、配置要素がビューポートや包含ブロックに収まらないときに、別のスタイルを指定することができます。このフォールバックは position-try-fallbacks プロパティ、もしくはショートハンドプロパティの position-try で指定します。

ここでもまた、選択肢が多く圧倒されてしまうのですが、大きく分けて以下の方法があります。

  • A. position-area のキーワードを指定する
  • B. flip- で始まるキーワードを指定する(<try-tactic>
  • C. @position-try で独自のルールを定義する
  • D. 別のアンカー名を指定する
position-try-fallbacks プロパティのパターン例
/* 共通スタイル */
.anchor {
  anchor-name: --anchor;
}
.another-anchor {
  anchor-name: --another-anchor;
}
.a, .b, .c, .d {
  position: absolute;
  position-anchor: --anchor;
  position-area: start span-all;
}

/* `A. position-area` のキーワードを指定する */
.a {
  position-try-fallbacks: end span-all;
}

/* `B. flip-` で始まるキーワードを指定する */
.b {
  position-try-fallbacks: flip-block;
}

/* `C. @position-try` で独自のルールを定義する */
.c {
  margin-block-end: 8px;
  position-try-fallbacks: --try-block-end;
}
@position-try --try-block-end {
  position-area: end span-all;
  margin-block-start: 8px;
  margin-block-end: 0;
}

/* D. 別のアンカー名を指定する */
.d {
  position-try-fallbacks: --another-anchor;
}

また、position-try-fallbacks プロパティには、カンマ(,)で区切って複数の値を指定できます。先頭から順番に試され、収まった場合に適用されます5

position-try-fallbacks に複数の値を指定した例
.a {
  position-try-fallbacks: end span-all, flip-block, --try-block-end, --another-anchor;
}

ここからは具体的に、flip-block を指定して、要素がスペースに収まらないときに垂直方向に反転する例を見ていきます。

position-try-fallbacks プロパティの例
.avatar {
  anchor-name: --avatar;
}
.hello {
  position: absolute;
  position-anchor: --avatar;
  position-area: start span-all;
  position-try-fallbacks: flip-block;
}

以下のデモでは、垂直方向にスクロールしていくと、フキダシの要素が見切れないように、配置が上下に反転します。

Live Demo
アンカー要素

Foo!

アンカー要素

Bar!

アンカー要素

Baz!

このとき、フキダシが下に配置されたときには、しっぽの向きを上に変更したいのですが、そのためには、CSS Anchor Positioning Module Level 2 のコンテナクエリ(anchored コンテナ)が必要になります。

この anchored コンテナは、執筆時点では Firefox と Safari が非対応であり、これ以上の説明を割愛しますが、また折を見て取り上げたいと考えています。

position-try 関連の機能は、これまでの CSS には見当たらないレジリエントなものですが、意図したとおりに指定するにはコツが必要で、難しく感じます。また、デザインとの制約にも関わるので、場合によってはデザイン担当者と実装担当者との間での調整も必要となるでしょう。

この記事では、Anchor Positioning の基本的な機能を説明しました。

すべての機能を紹介することはできませんでしたが、このほかにも、フォールバック時にスペースの優先度を指定する position-try-order プロパティや、配置要素の見え方を定義する position-visibility プロパティがあります。

Anchor Positioning は機能が豊富で、自由度の高い仕様です。それゆえに、理解するのには苦労しますが、新たな CSS レイアウトの可能性を感じさせてくれます。

次回は、より実践的な Anchor Positioning の例をいくつか取り上げて、Anchor Positioning の可能性を掘り下げていきたいと考えています。

本記事の作成にあたり、以下のウェブページを参考にしました。

脚注

  1. 執筆時点では、Anchor positioning の Baseline は Limited availability となっています。これは、position-anchor の一部の機能をサポートしていないブラウザがあるためだと考えられます(Anchor positioning | Web features explorer)。

  2. Anchor Positioning は Interop 2025 に選ばれていましたが、仕様の明確化や機能の信頼性向上などのため、引き続き Interop 2026 に持ち越されています(Announcing Interop 2026 | WebKit)。

  3. とはいえ、popover のデフォルトのスタイル(UA スタイルシート)をリセットするのは面倒なため、暗黙的なアンカーを回避したくなるのも理解できなくはないです。

  4. Experiment: Animating CSS position-area with View Transitions | Bram.us

  5. position-try-order プロパティを使用することで、単に先頭からの順番のみではなく、縦横どちらかのサイズを優先させることもできます。