transition无法实现真正惯性滑动,因其声明式、单次、不可中断,缺乏运行时速度反馈;需js计算拖拽速度与目标位置,transition仅负责收尾动画,配合非线性cubic-bezier曲线和精准边界处理。

纯 transition 无法真正模拟惯性滑动——它只能做线性或预设曲线的「状态间补间」,而惯性需要速度衰减、超调回弹、可中断等动态行为。但你可以用 transition + 少量 JS 配合,低成本逼近接近真实手感的效果。
为什么 transition 自身做不到惯性
transition 是声明式、单次、不可中断的:它只响应属性值变化(比如从 transform: translateX(0) → translateX(-100px)),然后按指定时长和曲线匀速/变速走完。惯性滑动的核心是「根据拖拽结束时的速度,决定后续位移量和衰减节奏」,这必须在运行时计算,transition 没有运行时反馈能力。
常见误判是以为用 cubic-bezier(0.25, 0.46, 0.45, 0.94)(类似 iOS 弹性)就能替代惯性——它只是视觉上“像”,但无法响应不同初速度,也无法被用户中途拖拽打断并重算。
用 transition 实现“伪惯性”的关键配合点
真正可行的方案是:JS 负责捕捉拖拽速度、计算目标位置;CSS transition 只负责执行最终那段「收尾动画」。这样既保持 CSS 动画的高性能,又让逻辑可控。
- JS 在
touchend/mouseup后立即估算瞬时速度(如用最后 100ms 位移差 / 时间差) - 根据速度大小,动态设置目标
transform: translateX(Npx),并同时设置transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) - 如果用户在动画中再次拖拽,立刻清除
transition(设为none),转为手动位移,避免卡顿 - 超调(overscroll)需额外判断边界,靠 JS 控制是否允许短暂超出再回弹,
transition只管回弹那一段
transition 参数选型直接影响“惯性感”
收尾动画的 timing-function 必须选非线性曲线,否则毫无惯性错觉:
-
cubic-bezier(0.25, 0.46, 0.45, 0.94):iOS 风格,起始快、末端有轻微回弹余量 -
cubic-bezier(0.34, 1.56, 0.64, 1):更激进的弹性,适合卡片类展开/收起 - 避免
ease或ease-out:它们减速太早,看起来像“急刹”,不是惯性 -
duration建议控制在 0.3–0.6s:太短像突变,太长像迟滞;实际值应随位移距离微调(大滑动稍长,小滑动稍短)
注意:transition-property 务必只写 transform,不要用 all——否则可能意外触发 opacity 或 height 过渡,造成闪烁或布局抖动。
容易被忽略的边界陷阱
惯性滑动最常崩坏的地方不在动效本身,而在边界处理:
- 用户快速向左拖到底,松手后惯性继续左滑——此时必须立刻 clamp 到最小值,并用
transition回弹,不能让元素消失在视口外 - 回弹动画若用
transform: translateX(0)硬设,会丢失当前速度感;更好的做法是 JS 计算一个略大于边界的临时目标值(如 -10px),再过渡回边界(0px),形成自然“撞墙反弹” - 滚动容器若设置了
overflow: hidden,要确保父容器尺寸严格固定,否则transform位移可能被截断或触发重排 - 在 Safari iOS 上,
will-change: transform有时反而导致transition卡顿,真机测试前务必关闭该声明做对比
真正的惯性依赖 scroll-snap + overscroll-behavior + 自定义手势库(如 @use-gesture)才能稳定实现;transition 只能当最后一程的“刹车片”来用——轻、准、可替换。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











