不能直接给img设opacity或filter,因其会使整图及叠加内容整体变灰发虚、性能差且Safari兼容不稳;正确做法是用::before伪元素+position: relative父容器+rgba()背景色实现独立遮罩层。

直接用 CSS 就能实现图片遮罩层,不需要 JS,但必须控制好定位层级和透明方式——改 img 的 opacity 会连文字一起变淡,错;用 rgba() 背景或伪元素才是正解。
为什么不能直接给 img 设 opacity 或 filter: opacity()
因为这两者会让整个图片元素(包括可能叠加的文字、图标)整体变灰、发虚,且无法单独控制“遮罩色”;更糟的是,filter 还会触发重绘、影响性能,Safari 下兼容性也不稳。你真正要的不是“让图变淡”,而是“在图上盖一层半透色块”。
-
opacity: 0.6作用于整个img元素,子内容不存在,但视觉上就是整张图蒙尘 -
filter: opacity(0.6)效果类似,但文字边缘会模糊,DevTools 里能看到额外的合成层 - 正确思路:把遮罩当作一个独立图层,和图片并列,只影响背景区域
用 ::before 伪元素加 position: absolute 最通用
这是目前最可控、调试最方便的方式,适用于卡片悬停、封面图、Banner 区域等常见场景。
- 外层容器必须设
position: relative,否则::before会相对于body定位,遮罩乱飘 -
::before写content: ""+position: absolute+top: 0; left: 0; width: 100%; height: 100%,确保撑满 - 遮罩色用
background-color: rgba(0, 0, 0, 0.5),其中0.5是遮罩不透明度,调低更透,调高更压暗 - 加
transition: opacity 0.3s ease和:hover::before { opacity: 1 }实现平滑显隐
需要在遮罩上放文字或按钮?改用子 div 遮罩层
伪元素不能嵌套内容,一旦你要加标题、CTA 按钮或 SVG 图标,就得换成真实 DOM 节点。
立即学习“前端免费学习笔记(深入)”;
- 结构上用
<div class="img-wrapper"><img><div class="overlay">...</div></div> -
.overlay同样设position: absolute,且父级.img-wrapper必须有position: relative - 别漏写
width: 100%; height: 100%——空div默认高度为 0,不写就看不见遮罩 - 如果遮罩要响应点击(比如关闭弹窗),保持
pointer-events: auto(默认值);若纯挡内容,可设pointer-events: none,但此时它也不拦截点击了
遮罩层没盖住图片?先查这三件事
90% 的“遮罩失效”问题都出在这几个隐性细节上:
- 父容器是否意外触发了层叠上下文?比如加了
transform、opacity: 0.99、filter: blur(1px),会导致z-index失效 -
::before或遮罩div是否漏了top: 0; left: 0?没定位基准,100%宽高就失去意义 - 图片是
<img>标签还是background-image?后者需把遮罩层和图片都放在同一容器内,用伪元素或子div覆盖才可靠
真正难的不是写几行 CSS,而是理解「遮罩」本质是图层叠加关系,不是属性开关。一旦定位和层叠上下文理清,rgba() 和 ::before 就足够应对绝大多数需求;SVG <mask> 或 Canvas 方案,只在需要非矩形、羽化边缘或动态生成时才值得引入。



















