カーソルを合わせたときにツールチップを表示する

ユーザーは、コンテキストを完全に変更することなく、関連する追加情報を確認できることを期待しています。ユーザーが詳細情報を求めているときにツールチップを表示すると、用語の定義を提供したり、アイコンのみのボタンが実行するアクションを明確にしたり、フォーム フィールドの追加ガイダンスを提供したりするのに役立ちます。

ツールチップの作成

必要な動作を持つポップオーバーを作成するには、<div> 要素またはその他の意味的に適切な要素に popover="hint" 属性を追加します。ユーザーがツールチップを開くと、他の popover="hint" ツールチップは非表示になりますが、auto ツールチップや manual ツールチップは非表示になりません。また、ネストされたツールチップの非表示も処理します。

また、ライト ディスミス動作も提供されるため、ユーザーがポップオーバーの外側をクリックするか、フォーカスを移動すると、ポップオーバーは閉じられます。

ツールチップ要素には、一意の値を持つ id 属性が必要です。

<!-- MANDATORY: The tooltip container `<div>` must have a `popover` attribute.
     the value of `"hint"` ensures it can be "light dismissed". -->
<div popover="hint" id="tooltip">Tooltip content</div>

ユーザーが <a> 要素または <button> 要素にカーソルを合わせるかフォーカスして、追加情報に関心を示します。要素には、ツールチップの id 属性と一致する interestfor 属性が必要です。

<!-- The `interestfor` attribute can be applied to a `<button>` element: -->
<button interestfor="tooltip">Tooltip trigger</button>

<!-- The `interestfor` attribute can also be applied to an `<a>` element: -->
<a interestfor="tooltip" href="">Tooltip trigger</a>

トリガーには、トリガーを操作することで追加情報を利用できることを示す視覚的なインジケーターが必要です。

interestfor に組み込まれたユーザー補助機能

interestfor を使用すると、ブラウザが支援技術の配線を処理します。

  • 暗黙的なセマンティクス: popover="hint" を持つターゲットは、暗黙的に tooltip の最小ロールを取得します。role="tooltip" を自分で設定しないでください。
  • 暗黙的な関連付け: ターゲットがプレーンテキストの場合は aria-describedby を介して、ターゲットにインタラクティブなコンテンツが含まれている場合は aria-details を介して、ブラウザはソース要素をターゲットに暗黙的に関連付けます。トリガーに aria-describedby または aria-details を追加しないでください。
  • インタラクティブなコンテンツ: 必要に応じて関連付けが aria-details に切り替わるため、ターゲットにインタラクティブなコンテンツ(「インタレスト カード」内のリンクなど)を含めることができます。

ユーザー補助の制約(WCAG 1.4.13)

interestfor が上記のセマンティクスを処理する場合でも、実装は WCAG 1.4.13(ホバーまたはフォーカス時のコンテンツ)を満たす必要があります。

  • 閉じることができる: ユーザーは、ポインタのホバーやキーボード フォーカスを移動せずに(たとえば、Escape キーを押すことで)ツールチップを閉じることができる必要があります。ネイティブの popover 属性は、このバインディングを自動的に管理します。
  • ホバー可能: ポインタをツールチップのコンテンツ自体の上に移動しても、ツールチップが消えないようにする必要があります。これにより、拡大ツールを使用しているユーザーがツールチップのテキストを安全に読むことができます。
  • 永続的: ツールチップは、ホバーまたはフォーカスのトリガーが削除されるか、ユーザーが明示的に閉じるか、コンテンツが無効になるまで、表示されたままにする必要があります。

ツールチップの配置

ツールチップは CSS Anchor Positioning を使用して配置されます。interestfor を使用してツールチップを開くと、トリガー要素は自動的にポップオーバーの暗黙的なアンカーになります。

ネイティブ アンカー ポジショニングをサポートする最新のブラウザでは、トリガーに anchor-name を定義したり、ツールチップに position-anchor を定義したりする必要はありません。position-area を使用して、暗黙的なアンカーを基準としてツールチップを直接配置し、position-try-fallbacks を使用して衝突時の反転を処理できます。

[popover] {
  /* Implicit anchor from interestfor: no anchor-name or position-anchor needed */
  position-area: top;
  position-try-fallbacks: flip-block;
  margin: unset;
}

代替戦略

インタレスト インボーカーのフォールバックとブラウザ サポート

インタレスト インボーカーは、NPM の interestfor ポリフィル パッケージを使用して条件付きでポリフィルする必要があります。CDN を使用するよりも、ポリフィルをバンドルすることをおすすめします。

必須: HTMLButtonElement.prototype の interestForElement プロパティをチェックして機能を検出し、ネイティブ サポートがない場合にのみポリフィルを読み込みます。

<script type="module">
  if (!HTMLButtonElement.prototype.hasOwnProperty("interestForElement")) {
    // CDN link only used for example, prefer bundling.
    await import("https://unpkg.com/interestfor@latest");
  }
</script>

CSS ポリフィルの注意事項

ポリフィルを使用する場合、ネイティブの疑似クラスとプロパティのサポートがないため、CSS API が若干変更されます。

  • 疑似クラス: ポリフィルは実際の :interest-source 疑似クラスと :interest-target 疑似クラスを定義できないため、代わりに .interest-source クラスと .interest-target クラスを適用します。必須: :is() と組み合わせて、ネイティブ状態とポリフィル状態の両方をサポートします。
/* Styles to apply when the effect is being previewed */
:is(:interest-source, .interest-source) { /* ... */ }
:is(:interest-target, .interest-target) { /* ... */ }
  • CSS プロパティ: interest-delay、interest-delay-start、interest-delay-end の場合、ポリフィルはすべてのブラウザでカスタム プロパティを直接読み取ることができないため、CSS 変数を使用する必要があります。
/* Adjust the start and end delay for interest invokers */
[interestfor] {
  --interest-delay-start: 0.2s;
  interest-delay-start: var(--interest-delay-start);
  --interest-delay-end: 0.1s;
  interest-delay-end: var(--interest-delay-end);
}

Popover のフォールバックとブラウザ サポート

Popover API は主にプログレッシブ エンハンスメントですが、その定義動作である最上位レイヤのプロモーション、ライトディスミス、popovertarget 呼び出しには、CSS のみの同等の機能がありません。古いブラウザでは、ポリフィルが必要です。ポリフィルを配布したくない場合は、手動でフォールバックする必要があります。

ポリフィル: 古いブラウザで popover 属性をサポートするには、条件付きで @oddbird/popover-polyfill を読み込みます。必須: HTMLElement.prototype の popover プロパティをチェックして機能を検出し、ネイティブ サポートがない場合にのみポリフィルを読み込みます。無条件に読み込まないでください。

バンドラまたはインポート マップを使用する場合:

// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
  import("@oddbird/popover-polyfill");
}

バンドラを使用しない場合は、<script type="module"> 内の CDN からインポートします。

<script type="module">
  if (!("popover" in HTMLElement.prototype)) {
    import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
  }
</script>

スタイリングに関する注意事項: ポリフィルは実際の :popover-open 疑似クラスを定義できないため、代わりに .\:popover-open クラスを適用します。必須: :is() または :where() を使用して 2 つを結合します。そうしないと、:popover-open がないブラウザではルール全体が破棄されます。

[popover]:is(:popover-open, .\:popover-open) {
  display: block;
}

または、ポリフィルを使用しないレガシー フォールバックの場合は、position: fixed を使用して getBoundingClientRect() で座標を手動で計算するか、ユースケースで許容される場合は inset: auto でデフォルトの配置を使用します。

popover-polyfill は、popover をサポートしているが popover="hint" をサポートしていないブラウザでは、ヒントの動作をポリフィルしません。これらのブラウザでは、フォーカスによって開かれたツールチップが、ホバーによって 2 つ目のツールチップが開かれたときに開いたままになることがあります。

アンカー配置に対応していないブラウザをサポートするには、@oddbird/css-anchor-positioning ポリフィルを使用します。また、@supports を使用して代替位置を指定することもできます。

以前のブラウザをサポートするために @oddbird/css-anchor-positioning ポリフィルを使用する場合は、ポリフィルが暗黙的なアンカーやポップオーバーの position-area をサポートしていないことに注意してください。トリガーに anchor-name を明示的に設定し、ポップオーバーに position-anchor を設定し、position-area の代わりに anchor() インセット関数を使用して配置します。

<!-- MANDATORY: Conditionally install the anchor positioning polyfill -->
<script type="module">
  if (!("anchorName" in document.documentElement.style)) {
    await import("https://unpkg.com/@oddbird/css-anchor-positioning");
  }
</script>
button[interestfor="tooltip-attrs"] {
  /* MANDATORY: Each trigger and popover pair must have a unique anchor name, referenced by `anchor-name` on the trigger and `position-anchor` on the popover. */
  anchor-name: --tooltip-attrs;
}
#tooltip-attrs {
  position-anchor: --tooltip-attrs;
  /* If using the anchor positioning polyfill with a popover, DO use `anchor()` functions, and not `position-area. */
  top: anchor(bottom);
  left: anchor(right);
  margin: unset;
}