最稳的移动端半透明遮罩用 background-color: rgba(0, 0, 0, 0.5),避免 opacity;需确保元素有尺寸、伪元素加 content: "";全屏遮罩用 position: fixed + inset: 0;注意层叠上下文、深色模式适配及 transform 对渲染的影响。

移动端用 rgba() 实现半透明背景遮罩最稳
直接写 background-color: rgba(0, 0, 0, 0.5) 就行,别碰 opacity ——后者会让文字、按钮一起发虚,遮罩就失去意义。现代所有主流移动浏览器(iOS Safari 9+、Android Chrome 42+)都支持 rgba(),连微信内置 WebView(X5 内核 v6.13+)也没问题。
常见错误是写了 rgba() 却“看不见遮罩”,大概率因为元素没尺寸:空容器、没设 width/height、或子内容没撑开。伪元素(如 ::before)还必须带 content: "",否则不渲染。
- Alpha 值建议控制在
0.4~0.9之间:0.3以下压不住背景,0.95以上容易显脏、失去“透”的感觉 - 避免用小数位过多的 alpha,比如
0.45;改用0.4或0.5,某些旧版 Android WebView 对浮点精度处理不一致 - 深色模式下,
rgba(0, 0, 0, 0.5)在黑色背景上几乎不可见,得配合@media (prefers-color-scheme: dark)切成rgba(255, 255, 255, 0.3)
全屏遮罩必须用 position: fixed + inset: 0
写 position: absolute 的全屏遮罩,在 iOS Safari 滚动时会露底;用 width: 100vw; height: 100vh 也不可靠——vh 在地址栏收起/展开时会跳变。唯一稳的写法是:
mask {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.6);
}
注意:inset: 0 是 shorthand,等价于 top: 0; right: 0; bottom: 0; left: 0,兼容性比 inset 更广(IE11 也认四边全 0)。
立即学习“前端免费学习笔记(深入)”;
- 如果遮罩是伪元素(如
.popup::before),仍要加content: "" - 别在遮罩父容器上加
transform、filter或will-change,它们会隐式创建新层叠上下文,导致z-index失效 - 遮罩需响应点击(比如点空白关闭弹窗)时,确保没写
pointer-events: none
遮罩盖不住绝对定位元素?先查层叠上下文
典型现象:遮罩写了 z-index: 999,但里面一个 position: absolute 的按钮还是显示在它上面。这不是数值不够大,而是层叠上下文分裂了。
比如父容器同时用了 position: relative 和 opacity: 0.99,就会创建独立层叠上下文,遮罩和按钮的 z-index 就没法跨上下文比较。
- 检查遮罩层和目标元素是否同属一个层叠上下文:要么都放在同一个
position: relative容器内,要么把遮罩提到更高层级(如z-index: 9999)且其父容器不触发上下文 - 用 Chrome DevTools 的 “Layers” 面板能直观看到层叠上下文边界
- 移动端尤其要注意:某些安卓 WebView 对
transform: translateZ(0)的处理会意外创建上下文,慎用
边缘发虚、颜色偏移?加 transform: translateZ(0) 强制 GPU 渲染
iOS Safari 和部分安卓 WebView 渲染 rgba() 时,会对亚像素叠加做过度抗锯齿,导致遮罩边缘灰蒙蒙、深色模式下偏紫或偏青。
一行 transform: translateZ(0) 能强制启用硬件加速,多数情况立刻缓解。但它不是万能解药:
- 只对伪元素或有定位的遮罩层生效,直接写在
body上没用 - 别滥用:每个遮罩都加可能触发过多合成层,反而拖慢低端机
- 如果用了
backdrop-filter: blur(),translateZ(0)可能和模糊效果冲突,优先保模糊,再调 alpha 值补偿清晰度
真正麻烦的从来不是怎么写那行 rgba(),而是它被谁撑开、被谁截断、被谁挡住——尺寸、定位、层叠上下文,这三个点漏掉任何一个,遮罩就变成“看起来写了,其实没用”。


















