transition 必须写在常态规则中而非 :hover 里,否则移出时会跳变;需明确指定属性、避免 all 和 display 等不可过渡值,并适配 prefers-reduced-motion。

transition 必须写在常态规则里,不是 :hover 里
很多人把 transition 放在 :hover 块里,结果鼠标移开时样式“啪”一下跳回去——因为移出后规则失效,浏览器直接丢掉过渡逻辑。过渡效果只在属性变化时起作用,而变化必须发生在有 transition 声明的元素上,且该声明得一直存在。
正确做法是把 transition 写在非伪类的原始选择器中:
button {
background-color: #ccc;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #007bff;
}
-
transition必须写在常态(非:hover、非:active)的 CSS 规则中 - 哪怕只希望“悬停时动”,返回也想平滑,就必须让常态规则带过渡声明
- 如果用
transform或opacity,同样适用这条规则——它们也得在常态里加transition
避免 transition 被覆盖或重置
常见坑是多个 CSS 规则叠加导致 transition 被覆盖。比如组件库样式、重置 CSS、或者用了 all: unset 后没手动恢复过渡。
检查方式:打开 DevTools,选中元素,看 Computed 面板里 transition 是否生效;Hover 状态下它是否消失。
立即学习“前端免费学习笔记(深入)”;
- 不要用
transition: all 0.3s—— 它会让所有属性都过渡,包括你没想动的(比如height突然撑开) - 优先明确写出要过渡的属性:
transition: background-color 0.3s, transform 0.2s - 如果用了 CSS-in-JS 或 scoped style,确认
transition没被更高优先级规则干掉
hover 离开后过渡失效?检查是否触发了强制重排
有时候明明写了 transition,但移出时还是卡顿或跳变。大概率是 JS 或 CSS 在 hover 期间修改了影响布局的属性(比如 display: none、height: 0、visibility: hidden),导致浏览器放弃过渡,直接重绘。
-
display切换永远无法过渡——它是个离散状态,没有中间值 - 想隐藏又保持过渡,改用
opacity: 0+pointer-events: none,或transform: scale(0) - 避免在
:hover里改width/height的绝对值,改用transform: scaleX()更安全
需要更精细控制?用 prefers-reduced-motion 保底
用户开了系统“减少运动”偏好,transition 可能被浏览器静默降级。不处理的话,悬停效果会突然变生硬,尤其在 macOS 或 iOS 上。
显式适配能让体验更一致:
@media (prefers-reduced-motion: reduce) {
button {
transition: none;
}
}
- 这不是可选项,而是渐进增强的一部分——不加不会报错,但部分用户会觉得交互“抖”
- 别只靠 JS 检测
matchMedia,CSS 媒体查询更可靠、更早生效 - 如果项目已用动画库,确认其是否内置了该媒体查询兜底
transition,或者多写了一个 display。










