过去,开发下拉菜单常需编写大量 JavaScript 代码处理展开、收起、焦点管理及无障碍访问。更别提那无穷无尽的 z-index 层级大战了;移动端上按 ESC 键退出的逻辑直接罢工;至于那个'点击空白处自动关闭'的复杂逻辑,更是让人头疼。
HTML Popover API 已在 2025 年 4 月达成 Baseline Widely Available(基线广泛可用)状态!这意味着,它现在已经在 Chrome、Firefox、Safari 和 Edge 里实现了完美的跨浏览器支持。于是,我直接把那个复杂的组件彻底推翻,只用了区区 8 行纯 HTML 代码就搞定了一切——一行 JS 都没写!
没错,我说的就是 HTML Popover API——这是一种纯原生、声明式的终极魔法,能让你在完全不碰 JS 的情况下,轻松捏出各种浮层、提示框(Tooltip)、菜单和对话框。
回想过去这些年,为了搞个破浮层,前端兄弟们简直受尽了折磨:被 Popper.js 这种定位库来回摩擦,手动维护犹如黑洞般的 z-index 堆栈,绞尽脑汁地手写焦点捕获逻辑,还要像个老妈子一样自己去挂载各种无障碍 ARIA 属性。但现在,时代变了!浏览器大爷把这些脏活累活全包了。
这个月,我已经把这套黑科技实装到了四个线上项目中。结果呢?打包体积直接暴降 35KB!代码干净得令人发指,无障碍访问更是无可挑剔。
跟 JS 组件库说拜拜:纯享版 Popover
咱们先来搞懂这个能让你不写一行 JS、不调任何库,就能做出全功能浮层交互的神仙特性。
在旧的开发模式下,搞个浮层是这么玩的:你得用绝对定位把元素钉死,小心翼翼地防着 z-index 冲突,老老实实地写监听器来捕捉外部点击,手撸焦点捕获,加上 ESC 键监听,手动管理 ARIA 属性,最后还要用 JS 把这一大坨代码给串联起来。
// 传统写法示例
const button = document.querySelector('.trigger');
const popover = document.querySelector('.popover');
let isOpen = false;
button.addEventListener('click', () => {
isOpen = !isOpen;
popover.style.display = isOpen ? 'block' : 'none';
popover.style.zIndex = '9999';
if (isOpen) {
popover.setAttribute('aria-hidden', 'false');
// 还要手写焦点捕获...
// 还要加点击外部关闭监听...
// 还要加 ESC 键监听...
}
});
这还只是个能跑的半成品而已。你依然得去头疼焦点怎么管、位置怎么定、移动端怎么适配,以及那些繁琐的无障碍属性。
但是,Popover API 自打在 Chrome 114(2023 年 5 月)、Safari 17(2023 年 9 月)和 Firefox 125(2024 年 4 月)中陆续实装,并在 2025 年 4 月修成正果后,一切都变了。现在,你只需要贴上几个 HTML 标签:

