Notification API 仅支持 HTTPS 或 localhost 环境,HTTP 直开 HTML 会静默失败;dialog.showModal() 必须在用户激活的同步路径中调用,异步需 setTimeout(0) 绕过校验;alert/confirm 阻塞主线程,生产环境应禁用。

Notification API 必须走 HTTPS 或 localhost
直接双击打开本地 HTML 文件,Notification.requestPermission() 会静默失败,连授权弹窗都不出现。这不是 bug,是浏览器强制策略——只有安全上下文(HTTPS 或 localhost)才允许触发桌面通知。
常见错误现象:控制台没报错,但 Notification.permission 始终是 "denied" 或 "default",new Notification() 调用后什么也不发生。
- 开发阶段用
live-server、http-server或 VS Code 的 Live Server 插件起一个本地服务,地址变成http://localhost:xxxx就行 - 上线前确认域名已配置 HTTPS,HTTP 站点即使加了证书链也无效
- Safari 对
localhost支持较晚(15.4+),旧版需降级用alert()或标题闪烁
调用 showModal() 报 Failed to execute 'showModal' on 'HTMLDialogElement'
这个错误几乎只发生在异步上下文中:比如在 fetch().then()、setTimeout 或事件委托回调里直接调 dialog.showModal()。浏览器判定这不是“用户激活”行为,拒绝模态展示。
不是权限问题,是触发时机不合法。哪怕你刚点完按钮,只要中间穿插了 Promise 链或宏任务,就断开了用户操作链。
立即学习“前端免费学习笔记(深入)”;
- 最稳妥做法:把
dialog.showModal()放在原生点击事件的同步执行路径里,例如button.addEventListener('click', () => dialog.showModal()) - 若必须异步触发(如 API 返回后决定是否弹窗),可临时用
setTimeout(() => dialog.showModal(), 0)推到下一个宏任务——仅绕过校验,非长期方案 - 别用
dialog.style.display = "block"代替,它不触发模态栈、不锁背景、不支持 ESC 关闭
dialog 元素点击遮罩层不关闭?得手动判断 event.target
<dialog></dialog> 默认点击 backdrop(遮罩层)不会关闭弹窗,和多数 UI 库行为不同。这不是缺陷,是设计使然——避免误触,也方便做自定义交互(比如点击遮罩跳转链接)。
但用户习惯是点空白处关闭,所以得自己加逻辑。错误做法是给整个 dialog 绑 click 并 stopPropagation(),这会破坏屏幕阅读器聚焦和键盘 ESC 行为。
- 正确监听方式:
dialog.addEventListener('click', e => { if (e.target === dialog) dialog.close(); }) - 同时保留
dialog.close()调用,它比remove()安全:后者销毁 DOM,再次showModal()会报错 - CSS 中用
dialog::backdrop控制遮罩样式,注意 Safari 目前不支持设颜色,只能调background-color: rgba(0,0,0,0.5)的透明度
alert() 和 confirm() 别在主线程关键路径上用
alert() 和 confirm() 是同步阻塞式 API,执行时 JS 主线程完全冻结,页面所有动画、滚动、定时器都暂停。用户点确定前,整个 UI 处于假死状态。
典型翻车场景:表单提交成功回调里写 alert("提交成功"),用户点确定前无法关闭弹窗、无法切 Tab、甚至可能被浏览器标记为“无响应”。
- 现代页面中,仅限调试或内部工具使用;生产环境一律改用
<dialog></dialog>或轻量库(如sweetalert2) -
prompt()在 Chrome 95+ 已被禁用,且所有浏览器都不推荐——输入框样式不可控、移动端体验差、无障碍支持弱 - 如果必须兼容 IE11 或 Safari overlay(遮罩)、
modal(容器)、modal-content(内容),并手动处理tabindex="-1"和 ESC 键



















