正确做法是用伪元素::before或::after叠加半透色块并单独控制opacity过渡,需设父元素position: relative、伪元素content和overflow: hidden,避免影响子元素及触发重排。

hover 时用 opacity 实现遮罩过渡,但别直接改父元素
直接对包含图片和文字的容器设 opacity,会导致整个子内容(包括文字)一起变透明,这不是遮罩,是“褪色”。真正要的是只盖一层半透色块,且过渡平滑。
正确做法是用伪元素 ::before 或 ::after 叠在内容上方,单独控制它的透明度和过渡:
img {
position: relative;
display: block;
}
img::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.6);
opacity: 0;
transition: opacity 0.3s ease;
}
img:hover::after {
opacity: 1;
}- 必须给父元素(如
img或div)加position: relative,否则::after会相对 body 定位 -
background用rgba()而非opacity,避免影响子元素;opacity只用来做显隐过渡 - 过渡时间别设太长,
0.2s–0.4s是人眼感知自然的区间,超过0.5s就像卡顿
用 transform + opacity 组合避免重排重绘
纯 opacity 过渡虽简单,但在某些旧版 Chrome 或 Safari 下可能有闪烁。更稳的方式是加上 transform: translateZ(0) 强制 GPU 加速,或用 scale 配合透明度微调视觉节奏。
例如让遮罩“浮现”而非硬切:
立即学习“前端免费学习笔记(深入)”;
.card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.7);
opacity: 0;
transform: scale(0.95);
transition: opacity 0.25s ease, transform 0.25s ease;
}
.card:hover::before {
opacity: 1;
transform: scale(1);
}- 只对
opacity和transform做 transition,这两者不触发 layout,性能好 - 避免在 hover 中改
width、height、top、left等会触发布局计算的属性 - 如果容器本身有 border-radius,记得给伪元素也加相同值,否则圆角内会出现像素级错位
IE11 兼容:filter 替代 opacity + 降级处理
IE11 不支持 opacity 在伪元素上的过渡,但支持 filter: alpha(opacity=0)。不过它和 transform 冲突,得单独处理。
稳妥写法是用特性检测或直接写两套规则:
.cover::before {
opacity: 0;
transition: opacity 0.3s;
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.cover::before {
opacity: 1;
filter: alpha(opacity=0);
transition: none;
}
.cover:hover::before {
filter: alpha(opacity=70);
}
}-
@media查询里那段是 IE10+ 的 hack,不是所有构建工具都支持,上线前务必实测 - 别依赖
filter: blur()做遮罩模糊效果——IE 不支持,且现代浏览器中它开销大、易糊边 - 如果项目已放弃 IE,这段可全删;但凡还有 1% IE 流量,就得留个兜底,哪怕只是静默降级为无动画
遮罩文字层被 pointer-events 拦住怎么办
遮罩层盖上去后,下面的按钮或链接点不动了?默认 ::before 会拦截鼠标事件,即使它是半透明的。
最简解法是加一行 pointer-events: none 到伪元素上:
.item::before {
pointer-events: none;
/* 其他样式... */
}
.item:hover::before {
pointer-events: auto; /* 只有 hover 时才需要响应,比如点击遮罩关闭弹窗 */
}- 多数场景下遮罩只是视觉层,不需要交互,所以全程
none就够了 - 如果遮罩本身要响应点击(比如关掉浮层),就只在 hover 状态设
auto,否则用户移开鼠标后还残留点击区域 - 别给父容器设
pointer-events: none来“绕过”,那会把底下所有可点击内容一并禁用
实际写的时候最容易漏的是伪元素的 content 和 position,少一个就啥都不显示;还有就是忘了给父容器设 overflow: hidden,导致遮罩溢出圆角或边框。这些地方没报错,但效果直接消失,查起来反而最费时间。










