當使用者對連結感興趣 (透過懸停或聚焦),懸浮資訊卡會提供內容的互動式預覽。使用者會在前往連結前看到這項資訊,這項資訊會提供使用者需要的內容,或協助確認連結是否包含他們正在尋找的內容。
如果您需要純文字、非互動式的工具提示,而非結構化連結預覽,請參閱「在懸停時顯示工具提示」。
1. 觸發懸浮資訊卡
使用 Interest Invokers API 觸發懸浮資訊卡。這可確保資訊卡在懸停和聚焦時都會顯示,並自動處理無障礙功能連結。
- 在卡片容器中加入
popover="hint"屬性。使用hint,避免關閉可能開啟的不相關彈出式選單。 - 在觸發連結中加入
interestfor屬性,指向資訊卡的id。
<a href="/article" interestfor="article-preview">Article title</a>
<!-- The `id` must match the `interestfor` value on the trigger. -->
<div id="article-preview" popover="hint" class="hovercard">
<h2>The buzz on hummingbirds</h2>
<p class="byline">By Delphi Aguilar</p>
<div>
<img src="bird.jpg" alt="A vibrant hummingbird">
<p>Brief summary of the article...</p>
</div>
</div>
您不需要在懸浮資訊卡中加入內容的額外連結,因為這與觸發連結重複。
interestfor 內建無障礙功能
使用 interestfor 時,瀏覽器會為您處理輔助技術連線:
- 隱含語意:具有
popover="hint"的目標會獲得tooltip的隱含最小角色。請勿自行設定role="tooltip"。 - 隱含關聯:如果目標是純文字,瀏覽器會透過
aria-describedby隱含地將來源元素與目標建立關聯;如果目標包含互動式內容,則會透過aria-details建立關聯。請勿在觸發條件中加入aria-describedby或aria-details。 - 互動式內容:由於關聯會在需要時切換至
aria-details,因此目標「可以」包含互動式內容 (例如「興趣資訊卡」中的連結)。
2. 使用錨定定位功能
使用 CSS 錨定位置,根據觸發條件設定懸浮資訊卡的位置。使用 interestfor 時,觸發條件會成為彈出式視窗的隱含錨點。
[popover].hovercard {
/* Position the card below the trigger, aligned with its inline-start edge
and spanning toward the inline-end, flipping if it overflows the viewport. */
position-area: block-end span-inline-end;
position-try-fallbacks: flip-block, flip-inline;
}
3. 為進場和退場效果建立動畫
根據預設,鍵盤和滑鼠使用者會延遲半秒顯示和失去焦點。這樣一來,使用者在頁面上切換分頁或移動滑鼠時,就不會開啟目標彈出式視窗,而且將滑鼠從觸發條件移至彈出式視窗時,也不會關閉彈出式視窗。如要調整時間,請使用 interest-delay CSS 屬性。
[interestfor]{
/* Shorthand for interest-delay-start and interest-delay-end */
interest-delay: 0.2s 0.1s;
}
如果使用者可能會快速連續觸發多個彈出式視窗,請在使用者已開啟興趣觸發的彈出式視窗時,將初始延遲時間設為 0s。
:root:has(:interest-source) [interestfor] {
interest-delay-start: 0s;
}
使用 @starting-style 定義進場動畫,並使用 transition-behavior: allow-discrete (以及 display 和 overlay) 製作從頂層退場的動畫,將轉場效果限制在 @media (prefers-reduced-motion: no-preference) 後方。
[popover].hovercard {
opacity: 0;
transform-origin: top;
}
[popover].hovercard:popover-open {
opacity: 1;
transform: translateY(0) scale(1);
}
@starting-style {
[popover].hovercard:popover-open {
opacity: 0;
transform: translateY(-10px) scale(0.95);
}
}
/* MANDATORY: Respect user preference for reduced motion by selectively applying transitions. */
@media (prefers-reduced-motion: no-preference) {
[popover].hovercard {
transition:
opacity,
transform,
display,
overlay;
transition-duration: 0.4s;
transition-behavior: allow-discrete;
}
}
4. 選用:流暢地變形至下一頁
您也可以選擇使用跨文件檢視畫面轉換,在懸浮資訊卡和到達網頁之間建立流暢的「變形」動畫。如需實作指南,請參閱「一致的跨文件轉場效果」。
只要將相符的 view-transition-name 值指派給懸浮資訊卡中的元素,以及下一頁的對應元素,瀏覽器就會在導覽時為這些元素加上動畫效果。你可以指定多個元素 (例如標題、圖片、署名),建立複雜的多元素變形效果。使用 :popover-open 將 view-transition-name 指派給開啟彈出式視窗中的元素,避免建立重複的 view-transition-name 或需要連結專屬的 view-transition-name。
/* Opt-in to cross-document transitions on both pages */
@view-transition {
navigation: auto;
}
/* Don't show transitions when loading this page */
::view-transition-group(*) {
animation-duration: 0s;
}
/* Assign names ONLY when the popover is open to ensure only the correct elements are selected. */
[popover]:popover-open {
view-transition-name: --hovercard;
view-transition-class: morph;
h2 {
view-transition-name: --title;
view-transition-class: morph;
}
img {
view-transition-name: --image;
view-transition-class: morph;
}
}
必要:為確保轉換穩定且不會閃爍,到達網頁應使用 blocking="render" 和 <link rel="expect">,等待重要內容剖析完畢,再算繪第一個影格。
<!-- On the destination page: -->
<head>
<!-- Block rendering until the hero image and title are parsed,
ensuring the view transition snapshot is taken at the right time. -->
<link rel="expect" href="#main-content" blocking="render">
</head>
<body>
<main id="main-content">
<h1>The buzz on hummingbirds</h1>
<img src="bird.jpg">
</main>
</body>
/* On the destination page: */
main {
view-transition-name: --hovercard;
view-transition-class: morph;
}
h1 {
view-transition-name: --title;
view-transition-class: morph;
}
img {
view-transition-name: --image;
view-transition-class: morph;
}
/* By default no transition */
::view-transition-group(*) {
animation-duration: 0s;
}
/* Short transition for morphing elements */
::view-transition-group(.morph) {
animation-duration: 0.4s;
}
/* Disable transition if no `old` view */
::view-transition-new(.morph):only-child {
animation-duration: 0s;
}
備用策略
由於觸發條件是標準 <a href="..."> 連結,因此如果您選擇將懸浮資訊卡視為漸進增強,不支援的瀏覽器仍可在點選時導覽。如需跨瀏覽器懸浮資訊卡支援,請視需要有條件地載入 polyfill。
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 預設定位。
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);
}