答案是transition必须写在默认状态而非:hover中,否则移出时无过渡;需显式声明初始transform: scale(1)和transform-origin: center,并确保transition-property匹配实际变化属性。

这通常不是“只在移出时生效”,而是你误判了现象——真正的问题是:鼠标移入时有动画,移出时却“跳变”,看起来像移出才动;或者反过来,移入无反应、移出却有过渡。根本原因只有一个:transition 没写在默认状态里,或写错了属性匹配关系。
transition 必须写在常态选择器中,不能只放 :hover 里
浏览器过渡依赖「起始值 → 终止值」的插值计算。如果 transition 只出现在 :hover 中,常态下没有声明,那么移出时浏览器找不到“从哪开始过渡”,只能硬切回原始值。
- ❌ 错误写法:
.btn:hover { transform: scale(1.1); transition: transform 0.2s; }—— 移入有动画,移出瞬间跳回 - ✅ 正确写法:
.btn { transform: scale(1); transition: transform 0.2s ease; } .btn:hover { transform: scale(1.1); } - 必须显式写
transform: scale(1),不能省略。否则首次 hover 可能从none跳变,触发重排
transition-property 不匹配会导致“单向失效”
如果你在常态写了 transition: background-color 0.3s,但 :hover 里改的是 color 或 opacity,那移入也不会动——因为目标属性根本不在可过渡列表里。
- 检查实际变化的属性是否被
transition-property明确列出(比如transform、opacity、background-color) - 避免用
transition: all 0.3s:它会让所有可变属性都参与过渡,包括你没意识到的继承值(如box-shadow、border-color),反而导致移出时多等一堆无关动画 - 多个属性需过渡时,用逗号分隔:
transition: opacity 0.15s, transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
display / visibility 切换会彻底绕过 transition
如果你用 display: none/block 或 visibility: hidden/visible 控制显隐,那无论怎么写 transition 都不会生效——因为这两个属性不可插值。
-
display是离散值,浏览器无法计算 “none→block” 的中间态 -
visibility虽然可设transition,但它只有visible/hidden两态,没有缓动,视觉上仍是“开关式”切换 - 正确做法:用
opacity+transform+pointer-events: none模拟隐藏,并确保初始态和终态都定义了可过渡属性
transition-delay 在移出时“不翻转”,容易造成误解
transition-delay 是单向的:它只控制“状态变更后、过渡开始前”的等待时间。写在常态里,进和出都延迟;写在 :hover 里,只影响进入。
- 想实现“进快出慢”?别靠
delay,改用不同缓动函数:transition-timing-function: ease-in(进) vsease-out(出),但注意:必须两个状态都声明完整transition才能生效 - 想让移出后停顿 200ms 再淡出?纯 CSS 做不到“退出专属 delay”。得用 JS 控制类名切换时机,或改用
@keyframes+animation - 调试技巧:临时加
outline: 1px solid red到常态和 hover 状态,确认样式确实发生了预期变更
最常被忽略的一点:transition 是否生效,和你改的属性是否支持硬件加速强相关。比如用 left/top 移动元素,即使写了 transition,也可能因触发 layout 而卡顿甚至“看起来没动”;换成 transform: translateX() 就立刻平滑——这不是 transition 的问题,是属性选择错了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











