遮罩层必须用position: fixed+inset: 0(或top/right/bottom/left: 0),禁用width/height百分比或vw/vh以防漏边、偏移或裁剪;须配合box-sizing: border-box、rgba背景、同级弹窗结构及z-index上下文管理。

遮罩层必须用 position: fixed + 100vw/100vh,不能靠 width: 100% 和 height: 100% 填满视口——否则滚动条占位、嵌套 transform、overflow: hidden 等都会让它漏边、偏移或被裁剪。
为什么 box-sizing 和尺寸单位必须一起管?
遮罩层填不满,常不是定位写错了,而是盒模型和单位混用导致的隐性溢出:
-
width: 100%是相对于父容器计算的,而父容器可能没撑满视口(比如有padding或祖先设了overflow: hidden) -
width: 100vw锚定视口宽度,但若页面出现横向滚动条,100vw会变窄(滚动条占约 16px),保险写法是width: 100%; min-width: 100vw - 默认
box-sizing: content-box下,加border或padding会让实际占位超出设定宽高;统一加box-sizing: border-box才能确保width: 100vw真的“刚好盖住” - 别给遮罩层设
padding——它不是内容容器,留白应由弹窗自己控制
position: fixed vs position: absolute:什么时候该换?
绝大多数场景下必须用 position: fixed,只有在极少数局部遮罩需求里才考虑 absolute:
-
fixed直接锚定视口,滚动、缩放、键盘唤起都不会错位;absolute依赖最近已定位祖先,一旦中间某层加了transform或overflow: hidden,遮罩就可能被“关”在局部区域里 - 移动端 Safari 对
100vh在地址栏收起/展开时有轻微抖动,但比100%稳定得多;若真要兼容老 IE6,才需降级为absolute+ JS 动态算高宽(现已基本无需考虑) - 如果遮罩只用于覆盖某个模块(如卡片 hover 效果),且该模块本身是
position: relative,那absolute可行,但此时必须配inset: 0或显式top/left/bottom/right: 0,并确认祖先没触发层叠上下文
背景透明只能用 rgba(),禁用 opacity
opacity: 0.6 看似省事,实则是陷阱——它会让遮罩层内所有子元素(包括弹窗、按钮、文字)同步变淡,可读性直接崩坏:
- 正确做法:只设
background-color: rgba(0, 0, 0, 0.6),透明度仅作用于背景色本身 - 十六进制带 alpha(如
#0008)在旧版 Safari 和部分安卓 WebView 中渲染异常,优先用rgba() - 若需加阴影或描边,用
box-shadow或outline,它们不受rgba()影响,可独立控制 - 遮罩层内部不要塞内容;弹窗必须与遮罩同级(或作为其直接子元素),否则
z-index容易被中间某层悄悄创建的新层叠上下文截断
移动端和事件穿透的硬伤点
遮罩层在移动端真正难的不是样式,而是交互细节被忽略:
- iOS Safari 默认允许拖拽遮罩层,导致橡皮筋效果或偏移,必须加
touch-action: none - 点击遮罩关闭弹窗时,直接绑
click事件会导致点弹窗内部也触发关闭——因为事件冒泡;安全写法是e.target === e.currentTarget判断 - 某些 UI 库组件(如表格行内按钮)内部调用了
e.stopPropagation(),这时需改用捕获阶段:overlay.addEventListener('click', closeModal, true) -
pointer-events: auto(默认)适合点击关闭;若遮罩纯作视觉压暗,不希望拦截点击,则设pointer-events: none,让点击穿透到底层
真正容易翻车的地方不在 CSS 写几行,而在于 DOM 层级是否干净、祖先有没有悄悄加 transform 或 filter、以及移动端键盘唤起后视口高度重算是否被忽略——这些不会报错,但会让遮罩在特定设备上突然露白、错位或失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











