你以为点 dialog 外面只能靠 JS 监听?Chrome 134 用一个属性把这件事彻底原生化了
写过 dialog 的人都踩过这个坑——用户点蒙层背景关掉弹窗,这个 UX 预期从 PC 时代就存在,但 `
## 旧方法:12 行 JS 监听外部点击
“`js
dialog.addEventListener(“click”, (e) => {
const rect = dialog.getBoundingClientRect();
if (
e.clientX rect.right ||
e.clientY rect.bottom
) {
dialog.close();
}
});
“`
这里有个坑:`dialog` 本身也会触发 click 事件,而蒙层背景(`::backdrop`)实际上是 dialog 的一部分,所以要精确判断点击的是背景而不是 dialog 内容,才有了这套 `getBoundingClientRect` 判断逻辑。一个「点外面关闭」的简单需求,要写 12 行还要小心绕开这个坑。
## 新方法:一行 HTML 属性
“`html
“`
就这一行,浏览器原生处理所有判断。`closedby` 支持三个值:
– **`any`**:点蒙层背景 + 按 ESC 都能关闭,最接近 Popover 的行为
– **`closerequest`**:只有 ESC 能关,showModal() 打开时的默认值
– **`none`**:只能通过 JS 手动关闭,非 modal dialog 的默认值
## 为什么之前没有这个属性
`
Chrome 134 把这个能力带给了 `
## 完整例子:三种模式对比
“`html
点背景或按 ESC 都能关
请确认操作,无法点背景取消
这条提示只能手动关闭
“`
## 浏览器支持现状(2026 年 9 月)
– **Chrome 134+**:完整支持,默认启用
– **Safari**:behind flag,接近稳定
– **Firefox**:正向支持(mozilla/standards-positions #998)
– **全球覆盖率**:~67%,还不是 Baseline
由于覆盖率不到 80%,生产环境建议用 `@supports` 渐进增强:
“`css
@supports (attribute: dialog[closedby]) {
dialog[closedby=”any”] {
/* 安全使用 */
}
}
“`
## 三步下一步
1. **清理存量 JS**:项目中搜索 `getBoundingClientRect.*close()` 的 dialog hack,找到即替换成 `closedby=”any”`
2. **建立团队约定**:哪种弹窗用哪种模式——表单确认用 `closerequest`,工具提示用 `any`,安全提示用 `none`
3. **订阅规范更新**:Firefox 的实现进度可在 Mozilla 规范追踪库里查看,等全球覆盖率超 80% 再删除降级 JS
这个属性把 dialog 带到了和 Popover 同一个 UX 水平线上。以后判断一个交互「需不需要 JS」,先问浏览器有没有给属性——很多答案已经是「不需要」了。
评论区
登录后可评论。