你以为点 dialog 外面只能靠 JS 监听?Chrome 134 用一个属性把这件事彻底原生化了

写过 dialog 的人都踩过这个坑——用户点蒙层背景关掉弹窗,这个 UX 预期从 PC 时代就存在,但 `

` 元素从来没原生支持过。开发者只能写一段 JS:监听 dialog 的点击事件 → 用 `getBoundingClientRect` 判断点击坐标是否在 dialog 边界外 → 满足条件则 `dialog.close()`。这 12 行代码,复制粘贴了无数个项目。今天 Chrome 134 用一个 HTML 属性把这件事彻底原生化了。

## 旧方法: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


点外面或按 ESC 都关闭

“`

就这一行,浏览器原生处理所有判断。`closedby` 支持三个值:

– **`any`**:点蒙层背景 + 按 ESC 都能关闭,最接近 Popover 的行为
– **`closerequest`**:只有 ESC 能关,showModal() 打开时的默认值
– **`none`**:只能通过 JS 手动关闭,非 modal dialog 的默认值

## 为什么之前没有这个属性

`

` 在 HTML 规范里有两种打开方式:`showModal()`(modal,ESC 关闭)和 `show()`(非 modal,ESC 不响应)。对于 modal dialog,ESC 是平台级别的关闭手势,有明确规范。但「点蒙层关闭」从来不是 dialog 的原生行为——这个需求来自 Popover API(`popover=”auto”` 默认自带 light dismiss),开发者习惯之后就把这个预期迁移到了 dialog 身上,于是社区开始自己用 JS 实现。

Chrome 134 把这个能力带给了 `

`,WHATWG HTML 规范里 `closedby` 属性已经写入标准,Firefox 和 Safari 也在跟进。

## 完整例子:三种模式对比

“`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」,先问浏览器有没有给属性——很多答案已经是「不需要」了。

评论区

0 条评论

登录后可评论。