必须重置dialog默认样式,因chrome、firefox、safari ua样式差异大:chrome有16px外边距和阴影,firefox半透明,safari不居中且忽略border-radius;需设margin:0、显式padding、清空border,并用绝对定位替代居中逻辑。

dialog 默认样式为什么必须重置
Chrome、Firefox、Safari 对 <dialog></dialog> 的 UA 样式差异极大:Chrome 默认加了 16px 外边距和圆角阴影,Firefox 渲染为半透明块,Safari 甚至可能不居中或忽略 border-radius。不重置会导致布局错位、视觉割裂、iOS 上内容偏移——这不是“看起来不好”,而是“根本对不齐”。
关键点:<dialog></dialog> 的默认 margin 是浏览器硬编码的,margin: auto 无效;它的定位逻辑依赖干净的祖先链,父元素带 transform 或 will-change 会直接破坏居中。
- 必须设
margin: 0,否则 Chrome 下 dialog 总是下移一截 - 必须显式设
padding,否则 Safari 可能贴边无内边距 - 必须清空
border,因为 UA 默认是border: unset,部分浏览器渲染为细线 - 推荐用
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)替代依赖浏览器居中逻辑(尤其在嵌套容器中)
::backdrop 伪元素的样式限制与降级方案
dialog::backdrop 只支持极少数 CSS 属性:background、opacity、z-index,不支持 border、transform、filter,且 Safari 直至 v17.6 仍完全不支持该伪元素——写上去等于没写。
这意味着你不能靠 dialog::backdrop { background: rgba(0,0,0,0.4) } 在所有浏览器生效。真实项目里,要么接受 Safari 无遮罩(仅靠焦点锁定),要么手动补一层 DOM 遮罩:
- 只在 Safari 检测到
!CSS.supports('selector(::backdrop)')时,动态插入一个<div class="dialog-backdrop"> 并用 JS 控制显隐 <li>给 backdrop div 设 <code>position: fixed; inset: 0; z-index: 2147483646(比 dialog 默认 z-index 小 1) - 监听
dialog的close事件后同步移除 backdrop 元素 - 避免用
pointer-events: none,否则showModal()的焦点锁定会失效 -
<dialog></dialog>必须是的直接子元素——Safari v17.6+ 强制要求,嵌套在<div id="app"> 里,<code>showModal()会静默失败,::backdrop不渲染,Esc键无响应 - 脚本执行时机必须晚于 DOM 加载:不要在
里直接调dialog.showModal(),要包裹在DOMContentLoaded或放在前 - 首次显示必须用
showModal(),而非设置open属性或调用show()——open属性只控制可见性,不激活模态行为(无遮罩、无焦点锁、无 Esc 支持) - 在
<dialog></dialog>内部第一个可聚焦元素上加autofocus属性(如<input autofocus>或<button autofocus></button>) - 若动态生成内容,
showModal()后立即调用dialog.querySelector('[autofocus]').focus(),并用setTimeout包一层防竞态 - 关闭后,记得把焦点还给触发按钮:
dialog.addEventListener('close', () => triggerBtn.focus()),否则键盘用户按 Tab 会跳进不可见区域 - 别依赖
inert属性做背景禁用——它不被 Safari 支持,且和showModal()的原生焦点锁定冲突
初始化前必须检查的三件事
很多“dialog 不显示”“Esc 不响应”“遮罩点击无效”的问题,根源都在初始化阶段漏掉了基础校验。别跳过这三步:
autofocus 与焦点管理容易被忽略的细节
<dialog></dialog> 调用 showModal() 后,浏览器会尝试聚焦第一个可聚焦子元素,但这个行为很脆弱:如果第一个元素是 <div>、<code><p></p> 或 disabled 状态的 <button></button>,焦点就静默丢失——键盘用户卡在背景页,可访问性直接归零。
正确做法不是“等它自动聚焦”,而是主动干预:











