CSS Popover API + Anchor Positioning 完整教學:原生打造零 JavaScript 的浮動 UI 元件
你是否曾為了實作一個 tooltip 或 dropdown menu,引入了整個 Popper.js 或 Floating UI?這些 JavaScript 定位函式庫固然強大,但在 2026 年的今天,瀏覽器原生的 CSS Popover API 加上 Anchor Positioning 已經能讓你用純 CSS 完成大部分浮動 UI 元件的開發。這不只是減少 bundle size 的問題,更代表了前端開發正在回歸平台原生能力的趨勢。
Popover API 與 Anchor Positioning 解決了什麼問題
傳統的浮動 UI 開發面臨三大痛點。第一,定位計算複雜:tooltip 需要出現在按鈕的正上方、dropdown 要從按鈕下方展開,這些看似簡單的需求卻涉及大量的 JavaScript 計算,包含捲動偏移、視窗邊界碰撞偵測等。第二,z-index 管理混亂:多個浮動元件疊加時,z-index 容易衝突,需要建立全域的 stacking context 管理策略。第三,無障礙支援不完整:手動實作的 popover 經常遺漏鍵盤導航、焦點陷阱和 ARIA 屬性。
Popover API 和 Anchor Positioning 分別解決了這些問題。Popover API 提供了原生的彈出層管理,自動處理 top layer 渲染(不用再煩惱 z-index)、light dismiss(點擊外部自動關閉)和鍵盤事件。Anchor Positioning 則讓你用純 CSS 宣告元件之間的空間關係,取代了 JavaScript 的定位計算。
Popover API 基礎:popover 屬性與觸發方式
使用 Popover API 非常直覺。只要在 HTML 元素上加上 popover 屬性,它就成為一個可彈出的元件:
<button popovertarget="my-tooltip">顯示說明</button>
<div id="my-tooltip" popover>
這是一段說明文字
</div>就這麼簡單。不需要任何 JavaScript,瀏覽器會自動處理顯示與隱藏的邏輯。popovertarget 屬性指向 popover 元素的 ID,點擊按鈕就能切換其顯示狀態。
auto 與 manual 模式差異
popover 屬性接受兩種值,行為差異相當關鍵:
auto 模式(預設值)具備 light dismiss 功能。使用者點擊 popover 外部或按下 Escape 鍵,popover 會自動關閉。同一時間只能有一個 auto popover 處於開啟狀態,開啟新的會自動關閉舊的。這適合 tooltip、dropdown menu 等一次只需要顯示一個的場景。
manual 模式需要明確的開關動作才能控制顯示狀態。多個 manual popover 可以同時開啟,不會互相影響。這適合 toast 通知、持續性面板等需要共存的場景。設定方式為 popover="manual"。
你也可以用 popovertargetaction 屬性精確控制按鈕的行為,可選值有 toggle、show 和 hide。
Anchor Positioning 錨點定位詳解
Popover API 解決了彈出層的生命週期管理,但並沒有處理「定位在哪裡」的問題。這就是 Anchor Positioning 登場的時候了。
anchor-name 與 anchor() 函式語法
Anchor Positioning 的核心概念很簡單:先用 anchor-name 把一個元素標記為錨點,再用 anchor() 函式參照這個錨點來定位其他元素。
.trigger-btn {
anchor-name: --my-anchor;
}
.floating-panel {
position: fixed;
position-anchor: --my-anchor;
top: anchor(bottom);
left: anchor(center);
translate: -50% 0;
}上面的範例讓 .floating-panel 定位在 .trigger-btn 的正下方中央。anchor(bottom) 表示「錨點元素的底邊位置」,anchor(center) 表示「錨點元素的水平中心」。這比起 JavaScript 計算 getBoundingClientRect() 再手動設定 top 和 left 直覺太多了。
position-try-fallbacks 智慧回退機制
浮動元件最麻煩的問題之一是邊界碰撞:tooltip 預設出現在上方,但如果元素靠近視窗頂部怎麼辦?Anchor Positioning 用 position-try-fallbacks 優雅地解決了這個問題:
.tooltip {
position: fixed;
position-anchor: --trigger;
bottom: anchor(top);
left: anchor(center);
translate: -50% 0;
position-try-fallbacks: flip-block, flip-inline;
}flip-block 會在垂直空間不足時自動翻轉到另一側(上方不夠就跑到下方),flip-inline 則處理水平方向的翻轉。你也可以用 @position-try 定義完全自訂的回退位置,實現更精細的控制。
實戰範例:純 CSS Tooltip
結合 Popover API 和 Anchor Positioning,我們可以打造一個零 JavaScript 的 tooltip:
<button popovertarget="tip" style="anchor-name: --tip-anchor">
懸停查看
</button>
<div id="tip" popover
style="position: fixed; position-anchor: --tip-anchor;
bottom: anchor(top); left: anchor(center);
translate: -50% -8px;
position-try-fallbacks: flip-block;">
這是 tooltip 內容
</div>這個 tooltip 預設出現在按鈕上方,空間不足時自動翻轉到下方,點擊外部自動關閉。整個實作不需要一行 JavaScript。如果你對更多 CSS 新功能有興趣,可以參考 CSS Scroll-Driven Animations 的捲動動畫實作方式。
實戰範例:Dropdown Menu 下拉選單
Dropdown menu 是 Popover API 最經典的應用場景之一:
<nav>
<button popovertarget="menu" style="anchor-name: --menu-btn">
選單 ▾
</button>
<ul id="menu" popover
style="position: fixed; position-anchor: --menu-btn;
top: anchor(bottom); left: anchor(start);
margin: 4px 0; min-width: anchor-size(width);">
<li><a href="#">設定</a></li>
<li><a href="#">個人資料</a></li>
<li><a href="#">登出</a></li>
</ul>
</nav>注意 anchor-size(width) 這個函式,它能讓下拉選單的最小寬度等於觸發按鈕的寬度,讓視覺比例更協調。搭配 View Transitions API 還能為選單的展開收合加上流暢的過場動畫。
你可以進一步運用 CSS @scope 來限定 dropdown 內部的樣式作用範圍,避免樣式外溢影響其他元件。
瀏覽器支援度與漸進增強策略
截至 2026 年,瀏覽器對這兩個 API 的支援狀況如下:
- Popover API:Chrome 114+、Edge 114+、Safari 17+、Firefox 125+,全面支援
- Anchor Positioning:Chrome 125+、Edge 125+,Safari 和 Firefox 仍在實作中
由於 Anchor Positioning 的支援度還不是百分之百,建議採用漸進增強的策略:
.tooltip {
/* 基礎定位 - 所有瀏覽器都能用 */
position: fixed;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
}
@supports (anchor-name: --a) {
.tooltip {
/* 支援 Anchor Positioning 的瀏覽器使用錨點定位 */
position-anchor: --trigger;
top: anchor(bottom);
left: anchor(center);
translate: -50% 8px;
transform: none;
}
}用 @supports 偵測功能支援度,在不支援的瀏覽器中提供合理的 fallback 體驗。這和 CSS 原生 if() 條件邏輯 的漸進增強思路是一致的。
什麼時候還需要 JavaScript 定位函式庫
雖然原生 API 已經很強大,但以下情況你仍然需要 Floating UI 或類似的函式庫:
- 需要支援舊版瀏覽器:如果你的用戶大量使用 Safari 16 以前或 Firefox 124 以前的版本,Anchor Positioning 無法使用
- 複雜的定位邏輯:例如需要根據內容尺寸動態調整位置、或是實作 virtual element 定位(如右鍵選單跟隨游標)
- 動態內容更新:當 popover 內容在顯示後會動態改變尺寸,原生 API 的回退邏輯可能不夠靈活
- 高度客製化的動畫:entry/exit 動畫如果需要精確控制方向和時間軸,可能還是需要 JavaScript 輔助
對大多數的 UI 元件需求而言,CSS Popover API 加上 Anchor Positioning 已經足夠。建議的策略是:先用原生 API 實作,遇到真正無法解決的場景再引入函式庫。這樣能確保你的應用在效能和維護性上保持最佳狀態。
前端生態正快速朝向「原生優先」的方向發展。從 Popover API、Anchor Positioning、到 Scroll-Driven Animations 和 View Transitions,瀏覽器正在把越來越多原本需要 JavaScript 實作的功能收納進 CSS 標準中。擁抱這些原生能力,不只是追趕技術潮流,更是為了寫出更精簡、更高效、更易維護的程式碼。
繼續閱讀
CSS @function 自訂函式完整教學:原生取代 Sass Mixin 的新時代(2026)
CSS @function at-rule 已於 Chrome 139 正式推出,讓開發者能用純原生 CSS 撰寫可重用的自訂函式,涵蓋參數預設值、result 描述子與 if() 條件邏輯,是徹底取代 Sass Mixin 的關鍵一步。
相關文章
CSS @function 自訂函式完整教學:原生取代 Sass Mixin 的新時代(2026)
CSS @function at-rule 已於 Chrome 139 正式推出,讓開發者能用純原生 CSS 撰寫可重用的自訂函式,涵蓋參數預設值、result 描述子與 if() 條件邏輯,是徹底取代 Sass Mixin 的關鍵一步。
CSS light-dark() 函數完全指南:原生主題切換不再需要 JavaScript 2026
CSS light-dark() 函數是 2026 年最受矚目的 CSS 新特性之一,讓你無需一行 JavaScript 就能實現完整的深色/淺色主題切換系統。本文帶你從基礎到進階完整掌握這個強大的原生解決方案。
你可能也喜歡
探索其他領域的精選好文