CSS动画退出失效的根本原因是transition必须定义在基础选择器而非:not(:hover)等伪类上,否则退出时因样式瞬间切换而跳过过渡;正确做法是将transition声明在元素默认状态,仅用:hover修改属性值。

为什么 :not(:hover) 无法直接触发退出动画
因为 CSS 的 :not(:hover) 是一个静态匹配状态,不是“离开时”的事件钩子。浏览器不会在鼠标移出瞬间给它加过渡,而是立刻切换回未 hover 状态,导致动画被跳过或卡顿。
常见错误现象:transition: all 0.3s; 写在 :not(:hover) 上,结果只有 hover 进去有动画,退出时“啪”一下消失。
- 真正起作用的是元素自身的默认状态(比如未 hover 时的样式),不是
:not(:hover)选择器本身 -
:not(:hover)只是重写样式,不改变过渡触发时机 - 所有过渡必须定义在基础选择器上(如
.btn),而非伪类条件分支里
正确写法:把 transition 放在基础选择器,用 :hover 覆盖变化
过渡行为由“属性是否变化 + 是否有 transition 声明”共同决定,而 transition 必须稳定存在于元素生命周期中,不能只靠伪类临时挂载。
使用场景:按钮缩放、背景色渐变、图标位移等需要进退都平滑的交互。
button {
transform: scale(1);
background: #eee;
transition: transform 0.25s ease, background 0.25s ease;
}
button:hover {
transform: scale(1.05);
background: #333;
}
- 进和退共用同一组
transition声明,浏览器自动反向插值 - 避免在
:hover里再写transition,否则可能覆盖基础声明,导致退出无动画 - 如果只想让某个属性单向动(比如只进不退),得用 JS 控制 class,纯 CSS 做不到
遇到 opacity 或 visibility 时的特殊坑
visibility: hidden 不触发动画,opacity: 0 才可以;但若同时设 visibility: hidden 在 :hover 外,会导致元素不可见且无法触发 hover —— 因为它已经从渲染树“消失”了。
错误示例:button { visibility: hidden; transition: opacity 0.3s; } button:hover { visibility: visible; opacity: 1; } → 鼠标根本点不到。
- 想做淡入淡出,只用
opacity+transition,别混visibility - 真要彻底隐藏又保留交互区域,用
opacity: 0; pointer-events: none;配合:hover恢复 -
display: none完全不能参与过渡,任何时候都不要试图对它加transition
复杂交互动画建议用 prefers-reduced-motion 降级
用户系统开启“减少运动”时,硬编码的 0.3s 动画会照常执行,可能引发眩晕。这不是 bug,是没适配可访问性需求。
性能影响不大,但忽略它会让部分用户实际体验断裂。
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
- 别只靠 JS 检测,CSS 媒体查询更可靠、更早生效
- 用
!important是为了确保覆盖组件库或框架里写的内联 transition - 0.01ms 不是 0,是为了绕过某些浏览器对
0s的特殊处理逻辑
过渡时间不是写在 :not(:hover) 上的,它得从元素一出现就存在。很多人调了半天发现退出没动画,问题不在写法多巧妙,而在有没有把 transition 放对地方。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











