2026年9月25日
2026年9月25日
WordPressでCSS Anchor Positioning(アンカー位置指定)を使う方法:ツールチップをJSなしで配置する
CSS Anchor Positioning は、ある要素(アンカー)の位置を基準にして、別の要素をCSSだけで配置する仕組みです。ツールチップや用語解説、ドロップダウンメニューを「ボタンの真上に出し、画面端では反対側に逃がす」といった処理を、JavaScriptの座標計算なしで書けます。この記事では、WordPressのテーマに安全に組み込む手順と、未対応ブラウザへの備え、ブロックエディターで使うときのつまずきどころを説明します。
なお、ページ内リンク(#見出し へのジャンプ)の着地位置をずらす話とは別物です。固定ヘッダーに見出しが隠れる問題は scroll-margin-top で解決するもので、この記事の対象ではありません。名前が似ているため混同されやすい点に注意してください。
Anchor Positioning でできること
従来、ツールチップをボタンの近くに出すには、getBoundingClientRect() で座標を取り、スクロールやリサイズのたびに再計算する処理が必要でした。Floating UI などのライブラリが広く使われてきたのはこのためです。
Anchor Positioning では、次の3つを宣言するだけで位置関係が決まります。
- 基準にする要素に
anchor-nameで名前(--で始まる名前)を付ける - 配置したい要素を
position: absoluteかposition: fixedにし、position-anchorでその名前を指定する position-areaかanchor()関数で「アンカーのどちら側に置くか」を書く
さらに position-try-fallbacks を使うと、はみ出しそうなときに上下や左右を反転させる候補をブラウザに任せられます。スクロールに追従する再計算もブラウザ側が受け持つので、自前のスクリプトより軽く、ずれも起きにくくなります。
対応ブラウザの考え方
(2026年10月現在)Chrome と Edge はバージョン125以降で対応し、Safari もバージョン26で対応しました。Firefox は実装が進められている段階で、リリース状況は変わり続けています。最新の状況は MDN の各プロパティのページや Can I use で確認してください。
また、仕様の途中でプロパティ名が変わった経緯があります。古い記事に出てくる inset-area は現在の position-area、position-try-options は現在の position-try-fallbacks にあたります。古い名前で書いたCSSは新しいブラウザで効かないことがあるので、ネット上のサンプルを流用するときは名前を確認してください。
対応ブラウザが揃っていない以上、「未対応でも内容が読める」作りにしておくことが前提になります。具体的な書き方は後半で扱います。
手順1:子テーマに専用のCSSファイルを用意する
親テーマのファイルを直接編集すると、テーマ更新で消えます。子テーマ(ブロックテーマでも同じ)に assets/css/anchor.css を作り、functions.php から読み込みます。作業前にバックアップを取り、できればステージング環境で試してください。
<?php
// 子テーマの functions.php
add_action( 'wp_enqueue_scripts', function () {
$path = get_stylesheet_directory() . '/assets/css/anchor.css';
if ( ! file_exists( $path ) ) {
return;
}
wp_enqueue_style(
'wpdr-anchor',
get_stylesheet_directory_uri() . '/assets/css/anchor.css',
array(),
filemtime( $path ) // ファイル更新時にキャッシュを切り替える
);
} );
// ブロックエディター内のプレビューにも同じCSSを当てる
add_action( 'after_setup_theme', function () {
add_theme_support( 'editor-styles' );
add_editor_style( 'assets/css/anchor.css' );
} );
バージョン引数に filemtime() を使うのは、CSSを直したのに古いキャッシュが表示され続ける事態を避けるためです。数行だけなら「追加CSS」に書いても動きますが、テーマ内のファイルにしておくと差分管理やステージングからの反映がしやすくなります。
手順2:Popover API と組み合わせてツールチップを作る
単独でも使えますが、表示・非表示の切り替えを Popover API に任せると、開閉のJavaScriptも不要になります。ポップオーバーは最前面のレイヤー(トップレイヤー)に描画されるため、親要素の overflow: hidden や z-index に邪魔されにくいのも利点です。
HTMLは次の形です。ブロックエディターでは「カスタムHTML」ブロックに書きます。
<p>
記事の途中に出てくる
<button type="button" class="wpdr-tip-trigger" popovertarget="wpdr-tip-1">CLS</button>
という用語に解説を付けます。
</p>
<div id="wpdr-tip-1" class="wpdr-tip" popover>
CLS(Cumulative Layout Shift)は、読み込み中にレイアウトがずれる量を表す指標です。
</div>
CSSは次のとおりです。
/* assets/css/anchor.css */
.wpdr-tip-trigger {
anchor-name: --wpdr-tip-1;
}
.wpdr-tip {
/* ポップオーバー既定の中央配置を打ち消す */
inset: auto;
margin: 0 0 8px;
position-anchor: --wpdr-tip-1;
position-area: top; /* アンカーの真上 */
position-try-fallbacks: flip-block; /* 上が足りなければ下へ */
max-width: min(320px, 90vw);
padding: 0.75em 1em;
border-radius: 6px;
background: #1e1e1e;
color: #fff;
}
つまずきやすいのは inset: auto です。ブラウザ標準のスタイルでは、ポップオーバーは画面中央に置かれるよう inset: 0 と margin: auto が指定されています。これを打ち消さないと position-area が効いていないように見えます。
確認は、ボタンをクリックして真上に解説が出るか、ボタンを画面上端付近までスクロールしてから開いたとき下側に反転するかの2点で行います。開発者ツールの要素パネルでポップオーバーを選ぶと、適用されたアンカー関連のプロパティを確認できます。
手順3:同じ部品を複数置くときの名前の付け方
anchor-name はページ内で一意である必要があります。同じ名前を複数の要素に付けると、意図しない要素(文書順で後のもの)が基準になり、ツールチップが別の場所に飛ぶ不具合になります。
対処は2つあります。
- 部品ごとに名前を変える(
--wpdr-tip-1、--wpdr-tip-2…)。数が少なければ最も分かりやすい方法です。 anchor-scopeで名前の有効範囲を区切る。部品を包む要素にanchor-scope: --wpdr-tip;を書くと、その内側でだけ名前が解決されるため、同じ名前を使い回せます。ただし対応時期はプロパティごとに異なるので、使う前に対応状況を確認してください。
PHPのループでカードを出力する場合は、投稿IDを使って名前を作ると衝突しません。属性値は esc_attr() でエスケープします。
<?php
$anchor = '--wpdr-card-' . get_the_ID();
?>
<button type="button"
popovertarget="<?php echo esc_attr( 'wpdr-pop-' . get_the_ID() ); ?>"
style="<?php echo esc_attr( 'anchor-name:' . $anchor ); ?>">詳細</button>
<div id="<?php echo esc_attr( 'wpdr-pop-' . get_the_ID() ); ?>"
class="wpdr-tip" popover
style="<?php echo esc_attr( 'position-anchor:' . $anchor ); ?>">
<?php echo esc_html( get_the_excerpt() ); ?>
</div>
テーマのテンプレートから出力する分には問題ありませんが、投稿本文に style 属性を書く場合は注意が必要です。unfiltered_html 権限を持たないユーザーが保存すると、許可されていないCSSプロパティや popovertarget のような属性は除去されることがあります。この権限は、通常のサイトでは管理者と編集者が持ち、投稿者以下は持ちません(マルチサイトでは特権管理者のみ)。投稿者に書かせる運用なら、クラス名だけで使える形にしておくのが安全です。
手順4:未対応ブラウザと動きへの配慮
未対応ブラウザでは position-area などが無視され、ポップオーバーは標準の中央表示になります。読めなくはありませんが、意図とずれます。@supports で対応ブラウザにだけアンカー配置を当て、それ以外では素直な表示にしておくと混乱がありません。
@supports not (anchor-name: --a) {
.wpdr-tip {
/* 未対応ブラウザでは画面下部にシート状に表示する */
inset: auto 0 0 0;
margin: 0 auto;
max-width: 100%;
}
}
@media (prefers-reduced-motion: no-preference) {
.wpdr-tip {
transition: opacity 0.15s ease;
}
}
アニメーションを付けるときは、上のように prefers-reduced-motion で「動きを減らす設定にしていない人」だけに限定します。また、ポップオーバーはトップレイヤーに出るため、開いても本文の配置は動かず、CLS(レイアウトのずれ)の原因にはなりません。逆に、未対応時の代替として本文中に要素を差し込む作り方をすると、レイアウトがずれるので避けてください。
対応ブラウザを広げたい場合は、OddBird が公開しているポリフィル(@oddbird/css-anchor-positioning)や Floating UI などのライブラリを、必要なページだけで読み込む方法もあります。ただし読み込むスクリプトが増えるので、まずは代替表示で済むか検討してから判断するのがおすすめです。
アクセシビリティの確認
見た目の配置はCSSで解決しても、操作できるかは別に確認が必要です。
- 開くきっかけは
button要素にする。spanにクリック処理を付けるとキーボードで操作できません。 popovertargetで結んだボタンとポップオーバーは、Escキーで閉じる、外側クリックで閉じるといった基本動作をブラウザが提供します。独自に上書きしないでください。- 文字色と背景色のコントラストは WCAG 2.2 の基準(通常の文字で 4.5:1 以上)を目安にします。
- ホバーだけで出るツールチップは、タッチ端末やキーボード利用者が内容を読めません。重要な情報はクリックで開く形にします。
まとめ
- CSS Anchor Positioning は、アンカー要素を基準に別の要素をCSSだけで配置する仕組みで、ツールチップやメニューの座標計算を不要にします。
anchor-name、position-anchor、position-area、position-try-fallbacksが基本の4つ。古いinset-areaなどの名前は使わないようにします。- WordPressでは子テーマにCSSファイルを置き、
wp_enqueue_styleとadd_editor_styleで読み込みます。 - Popover API と組み合わせる場合は、既定の中央配置を
inset: autoで打ち消します。 - 名前はページ内で一意に。ループでは投稿IDから作り、属性値はエスケープします。
- 未対応ブラウザには
@supportsで代替表示を用意し、アニメーションはprefers-reduced-motionを尊重します。