1317 字
7 分鐘

HTML Popover API 怎麼用:用原生按鈕建立可關閉的浮層

做提示、篩選器或帳號選單時,很多專案會先引入一套浮層元件,然後才補定位、Esc 關閉與點擊外部關閉。若需求只是讓一段補充內容暫時浮在頁面上,HTML Popover API 已能處理這個基本互動。

直接答案是:可被使用者隨手關閉的輕量浮層用 popover="auto";必須由程式明確控制、不能點外部關閉的工具面板才用 manual。需要阻擋背景操作或要求使用者完成決策時,仍應使用 <dialog>。

最小可用範例#

把 popover 放在要顯示的元素,再讓按鈕的 popovertarget 指向它的 id:

<button type="button" popovertarget="filter-help">
篩選說明
</button>
<div id="filter-help" popover>
只會顯示符合目前分類的文章。
</div>

沒有填值的 popover 等同 popover="auto"。瀏覽器會先把浮層隱藏;按鈕被按下後顯示,再按一次切換回隱藏。auto 浮層也可用 Esc 或點擊外部關閉,並會在開啟另一個非巢狀 auto 浮層時關閉前一個。

這種宣告式關聯比手寫 aria-expanded、document click listener 更小,但不代表可以省略語意。按鈕名稱要描述動作,浮層裡的控制項仍應有自己的 label。

auto、hint、manual 與 <dialog> 分別解決什麼#

元件適合情況關閉方式不適合的情況
popover="auto"說明、選單、非關鍵提示按鈕、Esc、點外部需要強制回應的確認流程
popover="hint"已開啟選單旁的輔助提示關閉要求、點外部;另設離開/失焦處理支援範圍尚未確認的唯一操作入口
popover="manual"開發者工具列、持續顯示的小面板程式或自己的關閉按鈕讀者預期可點外部收起的選單
<dialog>刪除確認、登入、需要 modal 的表單close()、表單或明確按鈕只想展示一小段輔助內容

manual 不會 light dismiss,也不會因另一個 popover 出現而自動關閉。它適合已經有明確生命週期的面板;若只是把一般選單設成 manual,使用者很容易找不到收起它的方法。

提示出現時不想關閉選單,檢查 hint 與 fallback#

依 MDN 的 hint 說明,顯示 hint 不會把已開啟的 auto 浮層關掉;但這不代表點擊選單外部也不會關閉它,外部點擊仍可能觸發 light dismiss。若提示由 hover 開啟,還要支援鍵盤 focus,並在 mouseleave/blur 時明確隱藏。

支援一般 Popover API 不等於支援 hint。不支援 hint 的環境可能退成 manual,因此不能依賴點外部或 Esc 作為唯一退路。這個純顯示檢查可貼進目標瀏覽器 Console:

const probe = document.createElement('div');
probe.setAttribute('popover', 'hint');
console.log({
api: typeof probe.showPopover === 'function',
hint: probe.popover === 'hint',
});

此檢查只確認 API 與屬性辨識,不能證明關閉、焦點和定位都正確。若 hint 不可用,簡單說明可直接放在頁面上;不要用 CSS 隱藏重要提示,再等待一個不存在的 hover 開啟機制。本文於 2026-10-04 查核文件,尚未在各瀏覽器版本執行這份互動驗收。

Dialog 要用 modal 開啟方式#

所有 popover 都是非 modal,進入 top layer 或畫出 ::backdrop 也不會讓背景 inert。<dialog> 本身也不保證阻擋背景:show() 和 open 屬性是非 modal;需要 modal 時使用 showModal(),並保留清楚的關閉與取消流程。細節見 MDN dialog 文件。

原生按鈕與浮層的關聯不會自動提供完整 menu 鍵盤模型。若浮層中其實是一組一般連結,先保留連結語意;需要應用程式選單時,才連同方向鍵、焦點移動與 role 一起設計,不要只加 role="menu"。

需要 JavaScript 時,使用元素方法而不是 class 切換#

程式控制可用 showPopover()、hidePopover() 與 togglePopover()。先確認元素真的支援這些方法,才能在舊環境提供退路:

const help = document.querySelector('#filter-help');
if (help && typeof help.showPopover === 'function') {
help.showPopover();
} else {
// 這裡改顯示同一份說明的非浮層版本。
}

不要同時以 class 強制 display: block 來模擬開啟狀態;這會繞過 Popover API 的狀態與關閉規則。自訂外觀時可用 :popover-open,背景遮罩則用 ::backdrop:

#filter-help:popover-open {
max-width: 22rem;
padding: 1rem;
border: 1px solid #cbd5e1;
border-radius: 0.75rem;
}

上線前先測三件事#

  1. 用鍵盤開啟按鈕,按 Esc 後焦點是否仍回到合理的位置。
  2. 確認浮層內沒有放必填、不可忽略的流程;那是 dialog 或正常頁面區塊的工作。
  3. 在你的支援瀏覽器與實機上測試。Popover API 已列為 Baseline 2025,但舊版瀏覽器不在這個保證範圍內。

若同時使用選單與提示,另驗收「選單保持開啟時 hover 提示」「Tab 到提示觸發點」「點擊外部」「Esc」四條路徑;針對 hint 與定位分別檢查相容性。浮層尺寸會隨內容改變時,也可參考 ResizeObserver 回饋迴圈排查,避免量測與改尺寸互相觸發。

原生 popover 的價值是減少簡單互動的狀態管理,而不是取代所有 overlay 元件。先把「讀者可否忽略它」判斷清楚,元件選擇就會自然明確。

參考資料:

MDN:Popover API

MDN:Using the Popover API

MDN:dialog

HTML Popover API 怎麼用:用原生按鈕建立可關閉的浮層
https://laplusda.com/posts/html-popover-api-guide/
作者
Zero
發佈於
2026-07-31
許可協議
CC BY-NC-SA 4.0