opacity本身不支持渐变,需配合transition或@keyframes实现透明度过渡;常见失效原因包括未显式声明初始值、元素处于display:none、父级opacity叠加、硬件加速干扰等。

opacity 本身不支持“渐变”,只支持“过渡”;所谓“透明度渐变”实际是 opacity 值随时间平滑变化,必须配合 transition 或 @keyframes 才能动起来。
为什么写了 transition: opacity 0.3s 却没动画?
常见原因不是语法错,而是值根本没变或被阻断:
-
opacity初始值依赖浏览器默认(1),但未在 CSS 中显式声明,导致状态切换时无“起始值”可比对 - 元素处于
display: none状态——它已脱离渲染树,opacity过渡完全失效 - 父级设置了
opacity: 0.7,子元素再设opacity: 0.5实际是0.7 × 0.5 = 0.35,视觉变化极弱甚至不可察 - 同时用了
transform: translateZ(0)等硬件加速,在 iOS 14–15 WebKit 中可能跳过 opacity 插值
用 transition 实现 hover 淡入淡出的可靠写法
核心是「显式初始值 + 可触发的状态变更」:
- 必须在常态类中写明
opacity: 1(哪怕和默认值一样) - 用
:hover、.active或 JS 切换 class 来改变opacity值,不能只靠内联 style - 推荐搭配
ease-in-out,比linear更自然;0.25s–0.4s是较优时长,太短看不出变化,太长易感迟滞 - 移动端加
touch-action: manipulation防点击延迟导致过渡卡顿
.fade-btn {
opacity: 1;
transition: opacity 0.3s ease-in-out;
touch-action: manipulation;
}
.fade-btn:hover {
opacity: 0.6;
}
用 @keyframes 做自动循环淡入淡出
适合轮播、提示条等无需交互的场景,注意两点:
- 关键帧必须写全
0%、100%,且值明确(如opacity: 0→1→0),不能省略中间态 - 用
animation-fill-mode: forwards保持最终帧状态,否则动画结束会回退到初始值 - 避免在滚动容器里高频触发(比如
animation+scroll联动),iOS WebKit 容易掉帧
@keyframes fade-loop {
0%, 100% { opacity: 0; }
50% { opacity: 1; }
}
.blinking {
animation: fade-loop 3s infinite;
animation-fill-mode: forwards;
}
opacity: 0 的隐藏陷阱与替代方案
opacity: 0 的元素仍占布局、可聚焦、能响应事件——这常被当成“隐藏”误用:
- 若想彻底禁用交互,需额外加
pointer-events: none - 若要动画结束后真正移出文档流,不能靠
visibility: hidden(它不支持 transition),应在transitionend事件里用 JS 设置,或改用transform: scale(0)+opacity: 0后加overflow: hidden - 性能敏感场景(如列表项逐个淡入),优先用
opacity;局部渐隐(如文字右侧淡出)必须用mask-image,但要注意 Safari ≤ iOS 15.3 需伪元素降级
真正麻烦的不是写法,而是 opacity 的“副作用”——它影响整个元素及所有子节点,且无法局部控制。做 UI 动效时,先问一句:这里真的需要整块变透明,还是只是背景/文字某一部分要渐隐?选错方案,后面全是兼容性补丁。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











