transition实现页面淡出最轻量可控,需配合opacity与visibility两步控制,JS监听transitionend后卸载组件;animation遮罩易卡顿、z-index冲突且状态难同步,仅敏感信息等少数场景必要。

transition实现页面切换淡出比animation遮罩更直接
用 transition 控制 opacity + visibility 是最轻量、兼容性最好、也最可控的淡出方案。animation 配合遮罩(比如伪元素全屏覆盖)看似灵活,实则容易卡顿、触发重排、且路由切换时状态难同步。
常见错误现象:opacity: 0 后元素仍可点击/聚焦;用 @keyframes 做淡出但没配 visibility: hidden,导致过渡结束后占位还在;遮罩层 z-index 错乱,盖住新页面内容。
- 淡出必须配合
visibility: hidden(或display: none),仅靠opacity: 0不够 - 过渡时间统一写在离开态(即 .page-exit),避免新旧页面同时动效打架
- 别用
animation+forwards想“自动隐藏”,它不保证 DOM 更新时机,常导致新页面闪一下再出现
如何用transition实现安全的页面淡出
核心是两步:先触发动画类,等动画结束再卸载旧组件或跳转。关键不在 CSS,而在 JS 控制节奏。
使用场景:React/Vue 路由切换、单页内 tab 切换、模态框关闭。
- 给容器加基础样式:
.page { transition: opacity 0.3s ease, visibility 0.3s ease; } - 定义退出类:
.page-exiting { opacity: 0; visibility: hidden; } - JS 中先添加
page-exiting类,再监听transitionend事件(注意过滤opacity属性,避免visibility变化也触发) - Vue 用户慎用
v-if配合 transition,它默认用display: none,会跳过 opacity 过渡,应改用v-show+ class 控制
animation遮罩为什么容易出问题
所谓“遮罩”,通常是用 ::before 或绝对定位 div 盖住整个视口,先淡入遮罩,再切换页面,最后淡出遮罩。逻辑看似完整,但实际落地坑多。
性能影响:遮罩层强制触发合成层(尤其是加了 transform 或 will-change),低端机易掉帧;每次切换都新建/销毁遮罩节点,GC 压力大。
- 遮罩的
z-index必须高于所有页面内容,但又不能高于 toast、loading 等临时浮层,极易冲突 - 如果路由跳转快于遮罩动画完成(比如用户连点两次),遮罩可能残留,或新页面被意外遮住
-
@keyframes fade-out { to { opacity: 0; } }缺少visibility: hidden,动画结束后仍捕获事件 - 不支持 Safari 旧版本对
animation-fill-mode: forwards的解析,遮罩可能卡在半透明状态
真正需要遮罩的少数情况及替代思路
只有当你要「隐藏旧页面细节」(比如防止敏感信息闪现)或「模拟原生 App 页面推入/覆盖效果」时,遮罩才必要。否则,老老实实用 transition 更稳。
替代思路:不用全屏遮罩,改用局部遮罩(如只盖 header 或 content 区域);或用 clip-path 做方向性裁切,比 opacity + 遮罩更顺滑。
- 真要用遮罩,优先用
transform: scale(0)替代opacity,硬件加速更可靠 - 遮罩元素必须设
pointer-events: none,否则会拦截新页面点击 - 别在遮罩上加
transition,它只负责“显隐”,动效交给animation单独控制 - 务必测试 iOS Safari —— 它对
will-change: opacity和遮罩层叠加渲染有已知 bug
复杂点从来不在怎么写动画,而在于什么时候该停手、用最朴素的方式交出确定性。遮罩不是银弹,多数时候,一个干净的 transition 就够了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











