transition仅对可计算且有中间值的CSS属性有效,如transform、opacity、left等,其中transform因不触发重排且支持GPU加速而最推荐;display、visibility等不可过渡属性会导致动画截断或失效。

transition用在哪个CSS属性上才有效
轮播图滑动不自然,八成是transition写错了目标属性。不是所有属性都能触发平滑过渡——只有可计算的、有中间值的属性才行。left、top这类定位属性可以,但display不行;transform比left更推荐,因为不触发重排,GPU加速更稳。
常见错误:给opacity加transition却忘了同时控制visibility,导致元素突然消失,过渡被“截断”。
- ✅ 正确做法:对
transform: translateX()加transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) - ❌ 错误写法:
transition: left 0.4s+ 绝对定位 + 频繁JS改left值(重排开销大) - ⚠️ 注意:不要只写
transition: all 0.4s,会把不需要过渡的属性也拖进来,比如z-index变化会卡顿
为什么cubic-bezier比ease更可控
ease看着顺滑,但实际是固定曲线(cubic-bezier(0.25, 0.1, 0.25, 1)),轮播图常需要“快进慢出”或“先缓再急”,原生ease-in-out太平均,停顿感明显。
真实场景里,用户手指松开后滑动惯性要模拟得像物理运动,就得调贝塞尔曲线。浏览器开发者工具里可以直接拖动调节,但别瞎试——记住两个关键点:
立即学习“前端免费学习笔记(深入)”;
- 第一组值(x1, y1)控制起始加速度:y1越小,开头越“冲”(比如0.1)
- 第二组值(x2, y2)控制结束减速:y2越大,结尾越“刹得住”(比如0.94)
- 轮播常用组合:
cubic-bezier(0.25, 0.46, 0.45, 0.94)(iOS风格滑动)、cubic-bezier(0.34, 1.56, 0.64, 1)(带回弹感,慎用)
JS切换时class切换不生效或跳帧
用classList.add()切class触发动画,但经常一帧就闪过去,或者压根没动——根本原因是浏览器没来得及“看到”样式变化前的状态。JS执行太快,class加完立刻被覆盖,过渡没机会启动。
这不是CSS问题,是执行时机问题。必须让浏览器先“读取”旧状态,再“写入”新状态:
- ✅ 正确姿势:改完class后,强制触发一次
offsetHeight或getComputedStyle(el).transform,让浏览器同步计算 - ❌ 直接连写两行
el.classList.remove('active'); el.classList.add('next');,大概率失效 - ⚠️ 如果用
requestAnimationFrame包裹,记得放在remove之后、add之前,否则还是来不及
示例片段:
el.classList.remove('active');<br>void el.offsetWidth; // 强制reflow<br>el.classList.add('next');
移动端touch滑动时过渡被中断
手指拖拽过程中,如果一边滑一边松手,动画该继续惯性滚动,但常出现“突然卡住”或“直接跳到终点”。这是因为transition只响应CSS属性变化,而JS在touchend里直接设了最终位置,没留过渡时间。
关键不在CSS,在JS逻辑:必须判断松手瞬间的速度和方向,用transform + transition动态设置目标位移,并保留过渡。
- ✅ 惯性滚动要基于最后一次
touchmove的位移差和时间差算出速度,再乘以衰减系数 - ❌ 不要用
setTimeout延迟改位置——无法保证帧率,容易掉帧 - ⚠️ 切记:过渡时间不能写死,要根据预估滑动距离动态算,比如
transitionDuration = Math.min(600, Math.abs(distance) * 2)ms
真正难的不是写过渡,是让每一次transform变更都落在16ms内,且不被JS长任务阻塞。这点在低端安卓机上特别明显——滑动越快,越容易断帧。










