写了五年 tooltips,我现在用浏览器原生 API 替代了——Popover API 把这些场景全包了

做前端这么多年,tooltips、menus、action sheets 这些「覆盖层」组件我前前后后封装过七八套。每次都要处理定位计算、点击外部关闭、焦点管理、z-index 层叠……代码越写越多,效果还是时不时出问题。

2026 年了,浏览器终于给了一套原生方案——Popover API。

场景一:简单提示层,最少两行代码

以前写 tooltip,要监听 mouseenter/mouseleave,计算位置,还要处理滚动和 resize。现在一行 HTML 就够了:

<button popovertarget="mytooltip">悬停看我</button>
<div id="mytooltip" popover>这是提示文字</div>

给元素加 popover 属性,它自动获得 display: none;加 popovertarget 到 button 上,按一下就切换显示。不用写一行 JS。

auto vs manual:两种关闭行为

popover="auto" 时,点击外部或按 Esc 键会自动关闭——也叫「light dismiss」。这种适合 toast、teaching tips,一次只显示一个。

popover="manual" 时,必须显式关闭,适合多选菜单这类需要同时打开多个的场景:

<button popovertarget="menu1" popovertargetaction="show">菜单1</button>
<button popovertarget="menu2" popovertargetaction="show">菜单2</button>
<div id="menu1" popover="manual">内容1</div>
<div id="menu2" popover="manual">内容2</div>

定位不用自己算:anchor positioning

以前 tooltip 要跟着按钮走,得自己算坐标。Popover API 原生支持锚定:

.tooltip {
  position-anchor: --btn; /* 绑定到某个锚点 */
  position: absolute;
  bottom: anchor(top);    /* 显示在锚点上方 */
}

配合 position-try-fallbacks 还能自动处理边缘碰撞——贴边时自动换到下方或侧边。这在以前要手写一整套碰撞检测逻辑。

焦点和 Accessibility 不用操心

手动管理的覆盖层最烦的就是焦点管理——打开时焦点该去哪里,关闭后焦点该回到哪里。Popover API 自动处理:

  • 打开时,焦点自动移入 popover 内第一个可交互元素
  • 关闭时(通常是按 Esc),焦点自动回到触发按钮
  • 自动设置 aria-expanded 和隐式 aria-details,屏幕阅读器天然支持

事件监听:beforetoggle 和 toggle

如果需要动画或状态同步,两个事件够用:

popover.addEventListener(beforetoggle, (e) => {
  if (e.newState === open) {
    // 即将显示,可以在这里加动画类
  }
});

popover.addEventListener(toggle, (e) => {
  console.log(e.newState); // open 或 closed
});

beforetoggle 里还能 preventDefault() 阻止切换,适合做二次确认这类场景。

层叠问题不用再调 z-index

Popover 打开时会进入「top layer」——一个独立于普通文档流的层。这意味着什么?

  • 永远在最上层,不用跟 modal、dropdown、fixed 元素抢 z-index
  • 天然解决 overflow: hidden 截断问题
  • 配合 ::backdrop 可以给底层加模糊或遮罩效果:
.tooltip::backdrop {
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(2px);
}

现在能用在哪儿

截至 2026 年 7 月,所有主流浏览器都已支持 Popover API。MDN 的 Browser Compatibility 表格显示 Chrome 114+、Safari 17+、Firefox 125+ 全部覆盖。

什么场景不该用

Modal dialog(需要阻塞交互、强制用户做选择)还是该用 <dialog>showModal()——它有天然的焦点陷阱和返回机制。Popover 是 non-modal 的,适合可忽略的提示和操作。

下一步建议

如果你现在用的是第三方 tooltip 库(比如 floating-ui、tippy.js),可以先在一个非关键场景试点迁移——比如内部的 admin 后台,把新手指引、快捷操作提示这类非核心功能换成 Popover API,代码量能降不少,后续维护也省心。

主流框架(React、Vue)目前还没有官方封装,但原生 API 已经足够简单,封装一个基础 hook 或 composable 花不了半小时。

评论区

0 条评论

登录后可评论。

小鹿·界面实验室 1209 阅读