遮罩层必须用position: fixed+100vw/100vh,因width: 100%/height: 100%依赖父容器尺寸,易受滚动条占位、嵌套transform或overflow截断影响;而100vw/100vh锚定视口,更稳定,且需配合rgba背景、同级弹窗结构及z-index上下文管理。

遮罩层必须用 position: fixed + 100vw/100vh,否则在滚动、嵌套容器或移动端 Safari 下大概率漏边、偏移或被裁剪。
为什么不能用 width: 100% 和 height: 100%
这两个值依赖父容器尺寸,而遮罩层常挂载在 body 下——一旦页面有滚动条,100% 宽度会略小于视口(滚动条占位),导致右侧露白;在嵌套了 transform 或 overflow: hidden 的祖先里,它还会被截断或定位错乱。
-
100vw/100vh是视口单位,直接锚定屏幕边界,不随父级变化 - 移动端 Safari 对
100vh在地址栏收起/展开时有抖动,但比100%稳定得多 - 别写
top: 0; right: 0; bottom: 0; left: 0—— 某些安卓 WebView 会触发重绘抖动
background-color: rgba() 而不是 opacity
遮罩层若用 opacity: 0.6,其所有子元素(比如弹窗、关闭按钮)也会变透明,文字发虚、可读性崩坏。这不是“半透明遮罩”,是整块区域降级渲染。
- 正确做法:只给遮罩层设
background-color: rgba(0, 0, 0, 0.6) - 确保遮罩层内不放内容 —— 弹窗应与遮罩同级,而非它的子元素
- 如果真要往遮罩里加图标或按钮,必须单独设
opacity: 1覆盖,但不如拆开 DOM 结构干净
z-index 失效的常见原因
写了 z-index: 9999 却被盖住?大概率是某个祖先触发了层叠上下文,把遮罩“关”在局部环境里。
- 触发层叠上下文的属性包括:
transform、opacity、filter、will-change、z-index(非auto) - 遮罩层必须挂载在
document.body直接子级,避免中间某层悄悄创建新上下文 - 推荐用 CSS 变量统一管理:
--z-overlay: 100;、--z-modal: 110;,避免魔数冲突
点击遮罩关闭弹窗时的事件陷阱
直接给遮罩绑 click 事件会导致点弹窗内部任何地方都关闭 —— 因为事件会冒泡上来。
- 安全写法:
overlay.addEventListener('click', e => { if (e.target === e.currentTarget) closeModal(); }) - 如果弹窗组件内部调用了
e.stopPropagation()(如某些 UI 库表格),需改用捕获阶段:overlay.addEventListener('click', closeModal, true) - 移动端务必加
touch-action: none,否则 iOS Safari 会出现拖拽偏移或橡皮筋效果
真正难的不是写几行 CSS,而是让遮罩在各种嵌套、滚动、缩放、键盘唤起场景下都不错位、不透底、不误关 —— 这些细节堆起来,才是生产可用的遮罩层。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











