全屏 dialog 需设 position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; 并处理 safari 偏移、遮罩点击关闭、焦点管理及无障碍支持。

dialog 全屏显示要改哪些 CSS?
原生 dialog 默认是内容自适应尺寸,不是全屏。想让它铺满视口,不能只靠 width: 100vw; height: 100vh —— 这样会溢出、滚动条错乱,且 Safari 下常因父容器 transform 而偏移。
真正可靠的做法是用 position: fixed 覆盖默认定位逻辑,并手动控制层级和内边距:
dialog { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; margin: 0; padding: 0; border: none; }- 必须显式设
top和left,否则在 Safari 中可能居中而非贴边 - 加
z-index: 9999确保压过其他元素(::backdrop的 z-index 不可调,只能靠 dialog 自身) - 移动端需加
max-width: 100vw; max-height: 100vh防止缩放后内容撑破
showModal() 后怎么让内容垂直居中?
dialog 全屏后,内部内容默认顶对齐,不是视觉居中。别用 margin: auto 或 flex 套两层 —— dialog 的渲染机制会让某些 flex 行为失效(尤其在 Firefox 中)。
推荐直接用绝对定位 + transform,稳定跨浏览器:
- 给
dialog内第一个子容器(如<div class="dialog-body">)加:<code>position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - 避免对
dialog本身设display: flex—— 它会干扰焦点锁定和 backdrop 渲染 - 如果内容高度不确定,加
max-height: 80vh; overflow-y: auto防止超出视口 - 监听
dialog的click事件 - 用
dialog.getBoundingClientRect()获取弹窗区域 - 若
e.clientX和e.clientY落在该矩形外,说明点在遮罩上 → 调用dialog.close() - 注意:必须排除弹窗内可聚焦元素(如按钮、输入框)的点击,否则点按钮也会关
- 调用
showModal()后立刻dialog.querySelector('button, input, [tabindex]')?.focus() - 关闭后,用
triggerBtn.focus()把焦点还给打开按钮(不能只靠document.body.focus()) - 全屏弹窗必须带
aria-labelledby或aria-label,否则屏幕阅读器只读“dialog”,没上下文 - 别在全屏
dialog内用position: fixed子元素 —— Safari 会渲染错位甚至消失
点击遮罩关闭全屏弹窗的兼容写法
全屏 dialog 的遮罩(::backdrop)点击关闭,在 Chrome/Edge 可靠,但在 Safari(截至 17.6)根本无法通过 e.target === dialog 判断是否点在遮罩上 —— 因为 backdrop 不是真实 DOM 节点,事件路径不可靠。
安全方案是放弃依赖 e.target,改用坐标判断:
全屏 dialog 的焦点与无障碍陷阱
全屏不等于可访问。原生 dialog 调用 showModal() 后,浏览器尝试聚焦第一个可聚焦子元素,但这个行为在 Safari 中极不稳定 —— 尤其全屏时,首次打开常焦点丢失或卡在 body。
必须手动接管:
dialog 最容易被忽略的其实是 Safari 的渲染层限制:只要父容器有 transform、will-change 或 overflow: hidden,全屏弹窗就可能被裁剪、错位或 backdrop 不出现。这不是样式问题,是浏览器合成层 bug,必须从 DOM 结构源头规避。











