🎈 浏览器原生 Popover API 入门

CSS HTML Browser API ⭐⭐⭐⭐

为什么需要 Popover API?

Tooltip 看起来是简单的 UI 问题,但实际上有很多边缘情况:

  • 键盘用户 Tab 太快会跳过 tooltip
  • 屏幕阅读器可能 announc 两次或根本不 announc
  • 鼠标移动太快会闪烁
  • 小屏幕上会遮挡内容
  • 按 Esc 无法关闭

❌ 旧方式 (库)

  • ~60 行 JavaScript
  • 5 个事件监听器
  • 手动管理 ARIA 状态
  • 手动处理焦点

✅ Popover API

  • ~10 行声明式 HTML
  • 零 JavaScript 事件监听
  • 原生 ARIA 状态同步
  • 原生焦点管理

快速开始

1. 基本语法

<!-- 触发元素 -->
<button popovertarget="my-tooltip">?</button>

<!-- Popover 元素 -->
<div id="my-tooltip" popover="manual" role="tooltip">
    这是 tooltip 内容
</div>

2. popover 属性值

  • popover="auto": 点击外部自动关闭,焦点移出关闭
  • popover="manual": 只能手动关闭(按 Esc 或调用 hidePopover())

3. 控制行为

<!-- 只打开 -->
<button popovertarget="tip" popovertargetaction="show">显示</button>

<!-- 只关闭 -->
<button popovertarget="tip" popovertargetaction="hide">隐藏</button>

<!-- 切换(默认) -->
<button popovertarget="tip" popovertargetaction="toggle">切换</button>

无障碍支持

🎯 这就是迁移的最大动力!
  • 键盘支持: Tab/Shift+Tab 原生工作,Esc 关闭
  • 屏幕阅读器: aria-expanded 自动同步
  • 焦点管理: 关闭后焦点自动返回触发器
  • Lighthouse: ARIA 状态警告消失

仍需 JavaScript 的场景

1. 延迟关闭

// 鼠标移出后延迟 200ms 关闭
let hideTimeout;
const tooltip = document.getElementById('tip');

tooltip.addEventListener('pointerleave', () => {
    hideTimeout = setTimeout(() => {
        tooltip.hidePopover();
    }, 200);
});

tooltip.addEventListener('pointerenter', () => {
    clearTimeout(hideTimeout);
});

2. 悬停意图判断

浏览器不知道用户是有意悬停还是路过,这个逻辑仍需 JS。

何时仍用库?

  1. 大型设计系统: 需要集中管理、一致性
  2. 复杂定位: 嵌套滚动容器、碰撞检测
  3. CSS Anchor Positioning: 正在快速获得支持,可替代库
  4. 团队无障碍经验不足: 库可作为安全网
💡 建议: 先用 Popover API 替换一个 tooltip,感受有多少代码"消失"了。

浏览器支持

  • Chrome
  • Firefox
  • Safari
  • 查看详情: Can I Use

相关 API