最近在处理一个下拉菜单时,我发现为了管理展开、收起、焦点和无障碍访问(Accessibility),往往需要死磕几十行 JavaScript 代码。更别提那无穷无尽的 z-index 层级大战了;移动端上按 ESC 键退出的逻辑经常罢工;至于那个'点击空白处自动关闭'的逻辑,更是容易引入难以维护的 bug。
好在 HTML Popover API 已经在 2025 年 4 月达成了 Baseline Widely Available(基线广泛可用)状态。这意味着它现在已经在 Chrome、Firefox、Safari 和 Edge 里实现了完美的跨浏览器支持。我直接把那个复杂的组件彻底推翻,只用了区区几行纯 HTML 代码就搞定了一切——一行 JS 都没写!
没错,这就是 HTML Popover API。这是一种纯原生、声明式的方案,能让你在完全不碰 JS 的情况下,轻松捏出各种浮层、提示框(Tooltip)、菜单和对话框。
回想过去这些年,为了搞个破浮层,前端兄弟们简直受尽了折磨:被 Popper.js 这种定位库来回摩擦,手动维护犹如黑洞般的 z-index 堆栈,绞尽脑汁地手写焦点捕获逻辑,还要像个老妈子一样自己去挂载各种无障碍 ARIA 属性。但现在,时代变了!浏览器把这些脏活累活全包了。
跟 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 键监听...
}
});
// 点击外部关闭的破烂逻辑
document.addEventListener('click', () => {
(!popover.(e.) && !button.(e.)) {
isOpen = ;
popover.. = ;
}
});

