懸停時顯示工具提示

使用者希望看到其他相關資訊,但不想完全變更內容。當使用者想瞭解更多資訊時,顯示工具提示可提供字詞定義、說明僅有圖示的按鈕會執行的動作,或提供其他表單欄位指引。

建立工具提示

只要在 <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 錨點定位定位。使用 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;
}

備用策略

Interest invoker 的備用方案和瀏覽器支援

Interest Invoker 必須使用 NPM 的 interestfor Polyfill 套件,有條件地進行 Polyfill。建議您將 Polyfill 綁定,而非使用 CDN。

必要:檢查 HTMLButtonElement.prototype 上的 interestForElement 屬性,偵測功能,並僅在缺少原生支援時載入 polyfill。

<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 Polyfill 注意事項

使用 polyfill 時,CSS API 會稍微變更,以因應缺乏原生虛擬類別和屬性支援的情況:

  • 虛擬類別:Polyfill 無法定義實際的 :interest-source 和 :interest-target 虛擬類別,因此會改用 .interest-source 和 .interest-target 類別。必要:請與 :is() 搭配使用,同時支援原生和 polyfill 狀態。
/* 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,polyfill 需要使用 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 的對等項目。舊版瀏覽器需要 polyfill,如果不想提供,則需要手動備用方案。

Polyfill:如要在舊版瀏覽器中支援 popover 屬性,請視情況載入 @oddbird/popover-polyfill。必要:檢查 HTMLElement.prototype 上的 popover 屬性,偵測功能,並僅在缺少原生支援時載入 polyfill,請勿無條件載入。

使用套件組合器或匯入對應:

// 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>

樣式注意事項:Polyfill 無法定義實際的 :popover-open 虛擬類別,因此會改為套用 .\:popover-open 類別。必要:請使用 :is() 或 :where() 結合兩者,否則不支援 :popover-open 的瀏覽器會捨棄整個規則:

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

或者,如要使用不含 polyfill 的舊版備用方案,請使用 position: fixed,並透過 getBoundingClientRect() 手動計算座標,或在用途允許的情況下,使用 inset: auto 預設定位。

在支援 popover 但不支援 popover="hint" 的瀏覽器中,popover-polyfill 不會對提示行為進行 polyfill。在這些瀏覽器中,透過焦點開啟的工具提示可能會在透過懸停開啟第二個工具提示時保持開啟狀態。

如要支援不支援錨定定位的瀏覽器,可以使用 @oddbird/css-anchor-positioning polyfill。或者,您也可以使用 @supports 指定備用位置。

使用 @oddbird/css-anchor-positioning polyfill 支援舊版瀏覽器時,請注意,polyfill 不支援隱含錨點或彈出式視窗上的 position-area。在觸發條件上明確設定 anchor-name,在彈出式視窗上設定 position-anchor,並使用 anchor() 內嵌函式 (而非 position-area) 調整位置:

<!-- 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;
}