transition生效需同时满足属性可插值、有明确数值变化、状态被触发三个条件;仅opacity、transform等能计算中间值的属性支持过渡,display、auto高度等无效;必须配合:hover或JS改样式等触发机制,且避免滥用all和忽略timing-function差异。

transition 不是加了就动,得满足三个条件:属性可插值、有明确数值变化、状态被触发。漏掉任一环节,动画就静止不动。
哪些 CSS 属性能用 transition 动起来
只有「能算出中间值」的属性才支持过渡,比如 opacity、transform、background-color、width(但必须是具体像素或百分比,不能是 auto)。以下属性无效:
-
display:没有中间态,设display: none → block不会渐显 -
height或max-height为auto时:浏览器无法插值,要过渡高度,得写死数值,例如max-height: 0 → max-height: 200px -
position的值(如static → relative):本身无连续性,不触发动画
transition 必须配合状态变化才生效
它只描述「怎么变」,不负责「何时变」。常见触发方式有:
-
:hover、:focus、:active这类伪类——最常用,但仅限用户交互 - JS 切换 class:
element.classList.add('is-open'),且目标 class 中需包含被过渡的属性新值 - 直接改内联样式:
el.style.opacity = '0.5',但要注意:若前一帧未完成重排(如刚插入 DOM),可能跳过动画,必要时可强制读取el.offsetHeight触发 reflow
错误示范:transition: all 0.3s 写在元素上,但没写 :hover 也没用 JS 改样式——它永远不启动。
立即学习“前端免费学习笔记(深入)”;
别乱用 all,也别忽略 timing-function
transition: all 0.3s 看似省事,实则埋雷:
- 把不可动画属性(如
display)也纳入监听,无效还拖慢渲染 - 多个属性共用一个
timing-function,节奏容易打架;真要差异化控制,得拆开写:transition-property: opacity, transform; transition-duration: 0.2s, 0.4s; transition-timing-function: ease-in, cubic-bezier(0.2,0.8,0.4,1) -
ease是默认值,但多数交互需要更精准节奏:ease-out适合菜单展开(先快后稳),cubic-bezier(0.25, 0.46, 0.45, 0.94)更接近真实物理惯性
Chrome DevTools 的 Styles 面板里点 timing-function 小图标,能直接拖拽调曲线,比硬背参数靠谱得多。
transitionend 事件监听要防重和过滤
这个事件会在每个过渡属性结束时都触发一次,不是整个 transition 只发一次:
- 如果同时过渡
opacity和transform,会收到两条transitionend,需通过event.propertyName判断是哪个属性结束 - 事件可能冒泡或重复绑定,建议加
once选项:el.addEventListener('transitionend', handler, { once: true }) - 若过渡被新样式中断(比如 hover 还没完就移开了),
transitionend可能不触发,不能依赖它做关键状态切换
真正难的不是写对语法,而是判断「这个属性值变没变」「浏览器是否已计算出旧值」「触发时机有没有被覆盖」——这些细节不验证,动画就卡在半路。



















