This article was translated from Japanese by AI and may contain inaccuracies. For the most accurate content, please refer to the original Japanese version.
錨のイラスト

ポップアップが画面内に収まらない場合に自動的に表示位置を調整する CSS Anchor Positioning

CSS Anchor Positioning とは、特定の要素を Anchor(基準)としてツールチップなどの要素の位置を決定する機能の総称です。CSS Anchor Positioning を使用することで、Floating UI のように自動で画面内に表示されるツールチップやコンテキストメニューを実装できます。

Note

CSS Anchor Positioning は 2024 年 4 月現在 Chrome Canary でのみ利用可能です。

CSS Anchor Positioning とは、特定の要素を Anchor(基準)としてツールチップなどの要素の位置を決定する機能の総称です。CSS Anchor Positioning を使用することで、Floating UI のように自動で画面内に表示されるツールチップやコンテキストメニューを実装できます。

ポップオーバーの表示位置を調整する

冒頭の動画で使用されたコードを見てみましょう。ツールチップとして表示される要素はポップオーバー APIを使用しています。

<button popovertarget="menu">Open</button>
<div popover id="menu">
  <ul>
    <li><a href="#">Item 1</a></li>
    <li><a href="#">Item 2</a></li>
    <li><a href="#">Item 3</a></li>
  </ul>
</div>

ポップオーバー API とは他のページコンテンツの上に表示されるポップオーバーコンテンツを表示するための標準的な仕組みです。HTML 属性を用いて宣言的にポップオーバーの表示非表示を切り替えられるという特徴があります。

ポップオーバーの表示を制御するための要素に対して popovertarget 属性を指定します。この属性の値には、ポップオーバー要素の id を指定します。ポップオーバー要素には popover 属性を指定します。popovertarget 属性を指定した要素をクリックするたびに、popover 属性を指定した要素の表示・非表示が切り替わります。

上記のコード例を実行すると、「Open」ボタンをクリックしたタイミングでポップオーバーが表示されることが確認できます。このとき、ポップオーバー要素はブラウザのデフォルトのスタイルシートにより画面の中央に表示されます。

CSS スタイルを追加してポップオーバーの表示位置を修正できますが、ここでは CSS Anchor Positioning を使用してポップオーバーを表示する位置を指定しましょう。まずはポップオーバーの表示位置の基準となるアンカー要素を定義する必要があります。アンカー要素を定義するためには以下の 2 つの方法があります。

  • CSS プロパティ anchor-name を設定する
  • HTML 属性 anchor を設定する

CSS プロパティ anchor-name を使用する場合、アンカー要素の名前 CSS 変数と同じ命名規則(dashed-ident)を使用します。

.anchor {
  anchor-name: --my-anchor;
}

HTML 属性 anchor を使用する場合、アンカー要素とする要素の id を指定します。これにより暗黙的なアンカーが定義されます。

<button id="trigger" popovertarget="menu">Open</button>
<div popover id="menu" anchor="trigger">
  <ul>
    <li><a href="#">Item 1</a></li>
    <li><a href="#">Item 2</a></li>
    <li><a href="#">Item 3</a></li>
  </ul>
</div>

アンカーを作成することで、以下のようにポップオーバーがアンカー要素の近くに表示されるようになります。

さらに CSS の anchor() 関数を使用することで、アンカー要素の位置を指定できます。anchor() 関数は以下の 3 つの引数を受け付けます。

  • アンカー要素:CSS プロパティ anchor-name で定義したアンカー要素の名前。HTML 属性による暗黙的なアンカーを使用している場合には、この値を省略する
  • アンカーの位置:アンカー要素の位置を指定するキーワード。以下の値を受け取る
    • inside, outsideinside はアンカー要素の内側、outside は外側に配置する
    • top, right, bottom, left:アンカー要素の上下左右の位置
    • start, end, self-start, self-end:論理プロパティによるアンカー要素の位置指定
    • 50% のようなパーセンテージ値を指定する
  • フォールバック:引数に不正な値が指定された場合に使用する値

以下の CSS は、アンカー要素の右から 12px 離れた位置にポップオーバーを表示するスタイルを定義しています。

[popover] {
  top: anchor(top);
  left: calc(anchor(right) + 12px);
}

position-try-options によるフォールバック

ここまでは固定的な値を用いてポップオーバーの位置を指定してきましたが、現実のユースケースではポップオーバーをトリガーする要素の位置に合わせてポップオーバーが表示される位置を調整することが求められます。例えば、以下のようにボタンが画面の右端に配置されている場合、ポップオーバーが画面外に表示されてしまう問題が発生します。

従来まではこの問題は JavaScript を使用して解決する必要がありました。CSS Anchor Positioning では position-try-options というプロパティを使用することで、ポップオーバーの表示位置を調整できます。position-try-options プロパティは絶対位置に配置された要素が包含ブロックを超える場合に、代替の位置を指定するためのプロパティです。

この要素は @position-try で定義されたルールを使用するあるいは、あらかじめ定義された以下のキーワードのいずれかを使用できます。

  • flip-block:ブロック軸に関するプロパティ(例:margin-block-start, margin-block-end)を反転させる
  • flip-inline:インライン軸に関するプロパティ(例:margin-inline-start, margin-inline-end)を反転させる
  • flip-startstartend の値を反転させる(例:margin-block-start, margin-inline-start

これらの値は複数指定できます。以下のように position-try-options プロパティを使用すると、ポップオーバーが画面内に収まらない場合に自動的に表示位置が反転されるようになります。

[popover] {
  top: anchor(top);
  left: calc(anchor(right) + 12px);
  position-try-options: flip-block flip-inline;
}

まとめ

  • CSS Anchor Positioning を使用することで、アンカー要素を基準にして要素の位置を指定できる
  • アンカー要素を定義するためには CSS プロパティ anchor-name または HTML 属性 anchor を使用する
  • アンカー要素を元にポップオーバーの表示位置を調整するために anchor() 関数を使用する
  • position-try-options プロパティを使用することで、ポップオーバーが画面内に収まらない場合に自動的に表示位置を調整できる

参考

Comprehension check

Answer the following questions to deepen your understanding of the article.

アンカー要素を定義するために使用する CSS プロパティは何か?

  • anchor-name

    Correct!

  • anchor

    Try again

  • anchor-element

    Try again

  • anchor-id

    Try again

ポップアップが画面内に収まらない場合に自動的に表示位置を調整するためのプロパティは何か?

  • position-try-options

    Correct!

  • position-fallback-options

    Try again

  • position-adjust-options

    Try again

  • position-retry-options

    Try again