ツールチップやドロップダウン メニューを配置する際は、ページ上の別の要素を基準に配置することがよくあります。絶対位置指定を使用してこの効果を実現する方法はありましたが、より複雑な要件では、これまで JavaScript を使用してアイテムを配置していました。
CSS アンカー配置は、別の要素を基準として要素を宣言的に配置する方法を提供します。
テザリングの要素
要素をアンカーにするには、2 つのダッシュで始まる任意の文字列の anchor-name 値を指定します。これは、位置指定された要素がアンカーを見つけるために使用する識別子です。わかりやすい名前を付けると便利です。要素がさまざまな方法でアンカーとして使用される場合は、要素に複数のアンカー名を付けることもできます。
位置指定された要素をテザリングできるようにするには、いくつかのプロパティを設定する必要があります。まず、position: absolute または position: fixed を設定して、要素をドキュメントのフローから取り出し、フローティングさせます。
次に、position-anchor をアンカーに設定したアンカー名に設定して、テザリングするアンカーを設定する必要があります。
最後に、アンカーの配置方法を設定する必要があります。position-area については、このモジュールで後ほど詳しく説明します。
#anchor {
   anchor-name: --my-anchor;
}
#positionedElement {
     position: absolute;
     position-anchor: --my-anchor;
     position-area: end;
}
暗黙的なテザリング
ポップオーバーは、さらに簡単にテザーできます。popovertarget を使用したボタンを使用するか、showPopover({source}) で source を設定してポップオーバーを開くと、ポップオーバーにはすでに「暗黙的なアンカー」が設定されています。ポップオーバーはデフォルトで position: fixed でフローティングされているため、ポップオーバーを配置するには、位置を設定するだけです。
#anchor{}
#positionedElement {
  position-area: end;
  margin: unset;
}
潜在的なアンカーのスコープ設定
アンカーの配置をコンポーネントの一部として実装すると、ドロップダウン メニューのようなパターンを複数の場所で使用できるようになります。同じ anchor-name を複数回使用する場合、各配置要素が正しいアンカーを見つけるようにするにはどうすればよいですか?
JavaScript ソリューションでは、各アンカーに一意の ID を追加し、その ID を位置指定された要素から参照します。これは面倒なため、CSS には anchor-scope を使用したよりシンプルなソリューションがあります。
anchor-scope プロパティは、要素とその子孫の間でのみ一致するアンカー名を設定します。1 つ以上のアンカー名のリストまたはキーワード all を受け取り、定義されたすべてのアンカー名のスコープを制限します。
anchor-scope は、配置された要素とアンカー要素の両方の祖先で、同じ名前の他のアンカー要素を含まない要素に追加するのが理想的です。多くの場合、これは再利用可能なコンポーネントのルートにあります。
次の例は、同じ anchor-name を持つ繰り返し要素に anchor-scope を適用した場合の違いを示しています。この例では、すべての <img> 要素と画像バナーが --image アンカー名を参照しています。anchor-scope が <li> 要素に適用されている場合、position-anchor: --image はバナーと同じ <li> 要素内の <img> 要素のみと一致します。それ以外の場合は、最後にレンダリングされた <img> と一致します。
位置付け
要素をアンカーにテザリングしたので、次は要素を配置します。アンカー ポジショニングでは、position-area と anchor() 関数の 2 つのポジショニング方法が用意されています。
position-area
position-area プロパティを使用すると、1 つまたは 2 つのキーワードを指定して、アンカーの周囲に要素を配置できます。これは一般的なユースケースの多くをカバーしており、多くの場合、ここから始めるのが適切です。
position-area の仕組み
position-area は、アンカーと位置指定された要素の元の包含ブロックの端によって生成された領域に、位置指定された要素の新しい包含ブロックを作成することで機能します。
position-area には多くのキーワードがありますが、わかりやすくするためにいくつかのカテゴリに分類できます。Anchor-tool.com は、構文を調べるのに最適なツールです。
物理キーワード
物理キーワード top、left、bottom、right、center を使用できます。たとえば、position-area: top right は、アンカーの右上にある配置された要素を配置します。これらのキーワードには、y-start、x-start、y-end、x-end という物理軸の同等物もあります。
論理キーワード
論理キーワード block-start、block-end、inline-start、inline-end を使用することもできます。たとえば、position-area: block-end inline-start は、英語などの言語では、位置指定された要素をアンカーの下かつ左に配置します。ドキュメントの書き込みモードでは、ブロック軸のアンカーの後、インライン軸のアンカーの前に配置します。center は論理キーワードとともに使用することもできます。
論理キーワードを指定する場合は、軸を省略することもできます。ブロック軸を最初に、インライン軸を 2 番目に指定します。position-area: start end は position-area: block-start inline-end と同じか、position-area: inline-end block-start と同じです。
複数のグリッド領域にまたがる
これまでのところ、これらのオプションでは、配置された要素を単一のグリッド スペース内に配置することしかできません。物理プロパティまたは論理プロパティに span 接頭辞を追加すると、隣接する中央グリッド スペースが追加されます。position-area: span-top right はアンカーの右側に配置され、アンカーの下から配置された要素の元のコンテナ ブロックの上まで配置されます。
プルダウン メニューの一般的な位置領域は position-area: block-end span-inline-end です。
span-all キーワードは 3 行または 3 列にまたがります。
単一のキーワード
キーワードを 1 つだけ設定すると、もう一方の軸は自動的に設定されます。この機能は、ほぼ想定どおりに動作しますが、その仕組みを理解しておくと役立つ場合があります。
指定されたキーワードで軸が明確に示されている場合、もう一方の軸は span-all として計算されます。つまり、position-area: bottom は position-area: bottom span-all と同等であり、位置指定された要素はアンカーの下に配置され、包含ブロックの幅全体が使用可能になります。
一方、キーワードが軸を明確に示していない場合は、繰り返されます。position-area: start は start start と同等で、左から右に読む言語ではアンカーの左上に配置されます。
anchor() 関数
より高度なユースケースでは、position-area が要件を満たさない場合があります。anchor() 関数を使用すると、別の要素の位置に基づいて個々のインセット プロパティを設定できます。これは CSS の長さに解決されるため、計算や他の CSS 関数で使用できます。また、異なる側面を異なるアンカーにテザーすることもできます。
anchor() 関数は、アンカー名とアンカーの側面を受け取ります。要素にデフォルトのアンカーがある場合(position-anchor で設定されているか、ポップオーバーなどで暗黙的に設定されている場合)、アンカー名を省略できます。
.positionedElement {
  block-start: anchor(--my-anchor start);
  /*  OR  */
  position-anchor: --my-anchor;
  block-start: anchor(start);
}
フォールバック値
anchor() 関数のアンカーが見つからない場合、宣言全体が無効になります。これは、アンカーが位置指定された要素の後にレンダリングされる場合や、一致する anchor-name を持つ要素がない場合に発生する可能性があります。この問題を処理するには、フォールバックの長さまたは割合を設定します。
.positionedElement {
   block-start: anchor(--my-anchor, 100px)
}
上記の例では、位置指定された要素の左側の値は --focused-anchor に固定されていますが、その anchor-name は最初のボタンにカーソルが合わされているか、フォーカスされている場合にのみ存在します。anchor() 関数は長さに解決されるため、別のアンカーをフォールバックとして使用できます。フォールバックを指定しなかった場合、位置指定された要素は配置されません。
アンカー サイドのキーワード
アンカーの辺の値は、アンカーのどの辺を配置するかを選択します。position-area と同様に、アンカーの辺の値はさまざまな構文タイプをサポートしています。
| タイプ | 値 | 説明 | 
|---|---|---|
| 実機 | top、left、bottom、right | 物理キーワードはアンカーの特定の辺に対応しますが、設定する位置指定要素のインセットと同じ軸でのみ使用できます。 たとえば、 | 
| 側部 | inside、outside | 
 たとえば、 | 
| 論理 | start、end、self-start、self-end | 論理キーワードは、 | 
| 割合 | 0%~ 100% | パーセンテージ値は、指定された軸上のアンカーの開始位置から終了位置までの軸に沿って、配置された要素を配置します。 | 
この例は、指定された軸でパーセンテージ値が常に開始から終了に移動する方法を示しています。
anchor() の使用
anchor() は長さであるため、非常に柔軟です。max() や calc() などの CSS 関数を使用して値を操作できます。
制限事項として、インセット プロパティでしか anchor() 関数を使用できません。
上記の例では、開いている詳細パネルの背後に背景を追加しています。この背景は、別のパネルが開いたときにスムーズにアニメーション表示され、ホバーされた詳細パネルを含むように拡大されます。これを実現するために、min() を使用して 2 つのアンカー間の短い方の長さを選択します。
#indicator{
/*  Use the smaller of the 2 values:  */
  inset-block-start: min(
/*   1. The start side of the default anchor, which is the open `<details>` element  */
    anchor(start),
/*   2. The start side of the hovered `<details>` element.    */
    anchor(--hovered start,
/*     If no `<details>` element is hovered, this falls back to infinity px, so that the other value is smaller, and therefore used.   */
       var(calc(1px * infinity)))
  );
}
この例では、calc() を使用して、開いているパネルの周囲にインライン スペースを追加しています。
アンカーのサイズを使用する
anchor-size() 関数を使用して、アンカーのディメンションを配置された要素のサイズ、位置、マージンに使用することもできます。
anchor-size() はアンカー名を取得するか、デフォルトのアンカーを使用します。デフォルトでは、使用されている軸のアンカーのサイズが使用されるため、width: anchor-size() はアンカーの幅を返します。物理キーワード width と height、または論理キーワード block、inline、self-block、self-inline を使用して、目的の長さを指定することで、他の軸を使用することもできます。
オーバーフローの処理
プルダウン メニュー コンポーネントを作成し、アンカー ポジショニングを使用してプルダウン メニューを目的の場所に配置しました。しかし、メニューを画面の反対側に移動したり、ユーザー メニューに使用したりすると、ユーザー名が長すぎてメニューがはみ出してしまいます。突然、ドロップダウンが画面外に移動します。どうすればよいでしょうか。
CSS アンカー ポジショニングには、配置された要素がコンテナ ブロックの外に出た場合に、堅牢なフォールバック セットをすばやく構築できる組み込みシステムがあります。
フォールバック オプション
position-try-fallbacks ルールは、フォールバック オプションのリストを受け取ります。デフォルトの位置がオーバーフローすると、オーバーフローしない位置が見つかるまで、各オプションが順番に試されます。
フォールバック オプションとして任意の position-area 値を使用できます。この例では、英語などの左から右への書き込みモードでは、配置された要素はアンカーの下部に配置され、中央と右の列にまたがります。オーバーフローした場合は、アンカーの下に配置され、左側の列と中央の列にまたがります。それもオーバーフローする場合は、オーバーフローしても位置がデフォルトの位置に戻ります。
.positioned-element {
  position-area: block-end span-inline-end;
  position-try-fallbacks: block-end span-inline-start;
}
一般的なフォールバック ケースを処理する flip- キーワードもいくつかあります。flip-block と flip-inline は、ブロック軸とインライン軸で要素を反転させようとします。flip-block flip-inline と組み合わせて、両方の軸を反転させることもできます。flip-start 値は、アンカーの開始コーナーから終了コーナーまでの対角線に沿って、配置された要素を反転させます。
@position-try を使用してカスタムのフォールバック オプションを作成することもできます。これにより、余白や配置を設定したり、アンカーを変更したりできます。
@position-try --menu-below {
  position-area: bottom span-right;
  margin-top: 1em;
}
#positioned-element {
  position-try: --menu-below;
}
flip-block と flip-inline を @position-try フォールバック オプションに追加して、バリエーションを作成できます。
#positioned-element {
  position-try: --menu-below, flip-inline --menu-below;
}
上記の例では、ブラウザは次の手順に沿って処理を進め、オーバーフローしない解決策が見つかった時点で停止します。
- 要素は position-area: endでアンカーの右下に配置されます。
- オーバーフローした場合、要素は --bottom-span-rightという名前のカスタム フォールバック オプションで配置されます。このオプションでは、要素はposition-area: bottom span-rightで配置され、下部に余白が追加されます。
- オーバーフローした場合、要素は flip-inline --bottom-span-rightで配置されます。これは、カスタム フォールバック オプションとflip-inline(実質的にはposition-area: bottom span-left)を組み合わせたものです。
- オーバーフローした場合、要素は --use-alternateカスタム フォールバック オプションを使用して配置されます。このオプションでは、まったく異なるアンカーの下に要素が配置されます。
- オーバーフローした場合、要素は position-area: endを伴って元の配置に戻ります。これはオーバーフローすることがわかっている場合でも同様です。
フォールバック順序
デフォルトでは、初期位置がオーバーフローすると、ブラウザはオーバーフローしない位置が見つかるまで position-try-fallbacks の各オプションを試します。position-try-order を使用してこの動作をオーバーライドし、各フォールバック オプションをテストして、指定された軸で最もスペースの大きいオプションを使用できます。
軸は、論理キーワード most-block-size と most-inline-size、または物理キーワード most-height と most-width のいずれかで指定できます。
position-try-order と position-try-fallbacks は position-try の短縮形と組み合わせることができ、その場合は順序が先になります。
スクロール
ユーザーは、スクロールしたときにページがスムーズに移動することを期待しています。これを実現するため、ブラウザではスクロール時のアンカー位置の使用方法に制限が設けられています。
配置された要素を異なるスクロール コンテナ内のアンカーにテザーできますが、要素はアンカーの 1 つのスクロールに応じてのみ移動します。これがデフォルトのアンカーになります。これは、ポップオーバーの暗黙的なアンカーか、position-anchor の値のいずれかです。
アンカーがビューからスクロールアウトしても、配置された要素は表示されたままになります。アンカーが非表示のときに位置指定された要素を非表示にするには、position-visibility: anchors-visible を設定します。これは、アンカーがオーバースクロールされた場合だけでなく、visibility: hidden などで非表示になっている場合にも適用されます。
理解度を確認する
anchor() の side の有効な値はどれですか?
inside25%25px25px などの長さはフォールバック値として使用できますが、サイドにはパーセンテージのみを使用できます。block-startstartposition-area の有効な値はどれですか?
topblock-end inline-endblock-start block-endどのプロパティが anchor() 関数をサポートしていますか?
topmargin-leftinset-block-starttransform同じ anchor-name を持つアンカーが複数ある場合はどうなりますか?