可行但易错乱,关键在于三层状态分离:active(opacity:1,z-index:3,visible)、leaving(opacity:0,z-index:1,visible)、idle(opacity:0,z-index:0,hidden),须js精确控制切换,禁用z-index过渡,配合transform:translatez(0)防safari失效,并处理无障碍偏好。

直接用 opacity + z-index 做幻灯片淡入淡出,可行但容易卡在「上一个没退场、下一个已入场」的层叠混乱里。关键不是堆属性,而是控制「谁在顶层可见、谁在底层透明、谁该被移出渲染流」。
为什么单纯改 opacity 和 z-index 会错乱
常见错误是只写:.slide.active { opacity: 1; z-index: 2; },其他 slide 设 opacity: 0; z-index: 1;。问题在于:
-
opacity: 0的元素仍响应点击、仍占文档流、仍参与 stacking context 计算 - 多个
z-index值相近时,浏览器按 DOM 顺序兜底——后出现的元素自动压在前面的上面,z-index反而失效 - 没有明确「当前活跃页必须唯一顶层」的约束,JS 切换 class 时若异步或漏删,就会出现两页同时
opacity: 1
正确叠加逻辑:三层状态分离
每个 slide 应始终处于且仅处于以下一种状态:
-
active(显示中):
opacity: 1; z-index: 3; visibility: visible; -
leaving(正在淡出):
opacity: 0; z-index: 1; visibility: visible;(保留 visibility 是为了动画能走完) -
idle(完全隐藏):
opacity: 0; z-index: 0; visibility: hidden;(真正退出交互与渲染流)
必须靠 JS 精确切换这三类 class,不能只靠 hover 或 toggle 两个 class。例如切换时:先给即将离开的 slide 加 leaving,等 animationend 事件后再加 idle;同时确保只有唯一 active。
transition 和 animation 怎么选
淡入淡出是二态切换,transition 更轻量、更可控:
- 用
transition: opacity 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);比ease-in-out更自然(避免开头顿挫) - 不要对
z-index做 transition——它不支持过渡,只能突变;z-index变更必须在opacity动画开始前完成 - 如果需要「淡入→停顿→淡出」这类多阶段节奏,才用
@keyframes+animation,但得配animation-fill-mode: forwards锁定终态
移动端 Safari 的静默失效点
iOS 16+ 仍有概率出现「opacity 动画不动」,尤其在 position: fixed 弹层或快速连点切换时:
- 必须加
transform: translateZ(0)或will-change: opacity触发 GPU 合成(仅对 active/leaving 状态加,idle 状态去掉) - 避免在
input:focus或scroll事件中同步触发切换——加requestAnimationFrame包一层 - 检测
prefers-reduced-motion: reduce时,直接禁用 transition,用 JS 立即切换opacity值
最易忽略的是:淡出完成后没清掉 visibility: visible,导致 opacity: 0 的 slide 依然挡点击——这比动画卡顿更难排查。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











