使用 CSS 錨定定位建構工具提示或彈出式視窗時,如果元素會溢出可視區域,瀏覽器會自動將元素「翻轉」至備用位置。發生這種情況時,您可能需要調整定位內容的樣式,例如重新定位從定位內容指向錨點的箭頭。
錨定容器查詢可解決這個問題,讓您查詢元素的有效定位狀態,並據此套用樣式。如需一般錨定下拉式選單和彈出式選單定位,以及可視區域碰撞翻轉 (不重新設定方向箭頭樣式),請參閱「可視區域感知下拉式選單」。
問題
假設工具提示預設顯示在錨點上方。底部有「向下」箭頭。如果使用者捲動畫面,工具提示翻轉並顯示在錨點下方,箭頭就會指向錯誤方向,並位於工具提示的錯誤一側。
解決方案:錨定容器查詢
在定位元素上設定 container-type: anchored,即可將其轉換為查詢容器,瞭解自身的錨定位置狀態。接著,您可以使用 @container anchored() 查詢更新其子系或虛擬元素。
1. 建立工具提示和觸發條件
使用 Popover API 建立工具提示。透過 popovertarget 叫用彈出式視窗,會自動與觸發按鈕建立隱含錨定連結,因此不需要明確的 anchor-name 或 position-anchor。
<button popovertarget="tooltip" id="anchor" aria-describedby="tooltip">anchor</button>
<div id="tooltip" popover role="tooltip"></div>
重設彈出式視窗的內凹和邊界樣式,以便與錨定位置搭配使用,但僅限支援錨定位置的情況。
@supports (anchor-name: --my-anchor) {
[popover] {
inset: auto;
margin: unset;
}
}
2. 設定容器
將 container-type: anchored 套用至要定位的元素。這個元素也必須定義 position-try-fallbacks,才能啟用翻轉行為。
#tooltip {
position: fixed;
position-area: block-start;
position-try-fallbacks: flip-block;
/* Enable anchored container queries */
container-type: anchored;
}
3. 根據備用廣告設定樣式
使用 @container anchored(fallback: <value>),在特定備用廣告啟用時套用樣式。
與所有容器查詢一樣,@container 只能設定容器子系的樣式。建立箭頭的常見策略是使用 ::before 和 ::after 虛擬元素,這些元素會視為子系,可直接設定樣式。不過,如要設定工具提示本身的樣式 (如步驟 4 所示),我們會在工具提示中新增子元素,並在其 ::before 虛擬元素中建立箭頭。
<div id="tooltip" popover role="tooltip">
<div class="tooltip-content">Tooltip</div>
</div>
.tooltip-content::before {
/* Default "down" arrow for the 'top' position */
content: "▼";
position: absolute;
inset-block-end: 0;
inset-inline-start: 1rem;
}
/* Update to an "up" arrow when the 'flip-block' fallback (bottom) is active */
@container anchored(fallback: flip-block) {
.tooltip-content::before {
content: "▲";
inset-block-start: 0;
inset-block-end: auto;
}
}
4. 設定容器本身的樣式
如要在容器翻轉時變更容器本身的屬性 (例如 margin 或 background-color),請使用內部包裝函式元素。
- 將
container-type: anchored套用至外部定位元素。 - 指定
@container區塊內的內部元素。
@container anchored(fallback: flip-block) {
.tooltip-content {
border-radius: 0 0 .5rem .5rem;
margin-block-start: 0.25rem;
}
}
最佳做法
- 優先使用邏輯備用方案:在
position-try-fallbacks中使用flip-block和flip-inline等關鍵字,簡化查詢,自動處理 RTL 和不同書寫模式。 - 使用虛擬元素製作箭頭:工具提示箭頭純粹是裝飾,非常適合使用
::before或::after,可透過錨定容器查詢設定樣式,不需額外的 DOM。
備用策略
根據套用的備用位置調整箭頭位置,是漸進式增強功能,沒有其他方法可以因應備用位置。如要在不支援錨定位置容器查詢的瀏覽器中隱藏箭頭,請使用 @supports (container-type: anchored) 測試 CSS 支援。
@supports (container-type: anchored) {
.tooltip-content::before {
content: "▼";
}
}
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 API 的瀏覽器也不支援錨定位置,因此工具提示會顯示在畫面中央。