ease-in不适用于重力掉落,因其cubic-bezier(0.42,0,1,1)加速度不恒定,起始拖沓、中段突快;而真实自由落体位移∝t²需恒定加速度,拟合抛物线得更优值cubic-bezier(0.17,0.67,0.83,0.67)。

直接用 ease-in 做掉落动画,基本等于放弃重力感——它开头太“粘”,中间又突然抢速,完全不像物体受恒定加速度下落。
为什么 cubic-bezier(0.42, 0, 1, 1)(即 ease-in)不适用于重力掉落
真实自由落体位移 ∝ t²,意味着速度应随时间线性增加,即加速度恒定。而 ease-in 对应的 cubic-bezier(0.42, 0, 1, 1) 在 t=0 处斜率为 0(初速为 0 没问题),但加速度曲线本身不是线性的:它起始段“拖沓”,中段陡升,末端又收得急,视觉上像断电坠落,而非被重力持续拉拽。
更关键的是:浏览器对 cubic-bezier() 的插值是基于归一化时间的,不是解物理方程。你没法“算出”重力参数,只能拟合视觉惯性。
- 短距离掉落(如 40px)时,
ease-in几乎卡在起点半拍,毫无下坠动势 - 若同时控制
opacity,用ease-in会让淡入和位移节奏脱节,显得“飘” -
y1 = 0导致起始加速度为 0,缺乏真实物体释放瞬间的微小初动
真正可用的重力感贝塞尔值:cubic-bezier(0.17, 0.67, 0.83, 0.67)
这个值是对抛物线 y = t² 在 [0,1] 区间做的三次贝塞尔近似拟合,实测在多数设备刷新节奏下,比 ease-in 更“沉”、更有质量感。
立即学习“前端免费学习笔记(深入)”;
它不是玄学凑数:y1 = 0.67 抬高了起始斜率,让初速不为零、加速度更接近恒定;y2 = 0.67 控制末端减速更平缓,避免戛然而止。
- 动画时长建议 ≥
0.5s,太短(如0.3s)会压缩加速过程,失去“坠落”意味 - 必须只用
transform: translateY(),别碰top或margin-top,否则触发重排,掉帧明显 -
opacity若需同步淡入,也得用同一cubic-bezier(0.17, 0.67, 0.83, 0.67),保持节奏一致 - 别把
y1或y2写成负数或 >1 —— Chrome/Firefox/Safari 会静默降级为ease,DevTools 动画面板里曲线会变直线,但你不一定会注意到
想加一点“触底反馈”?用 @keyframes 微调关键帧
纯线性掉落没有物理反馈。真实物体落地会有微小回弹和阻尼,CSS 里靠关键帧“过冲 + 回稳”就能模拟,比拆成两个 animation 更稳。
例如目标位移是 translateY(80px):
.drop {
animation: drop 0.6s cubic-bezier(0.17, 0.67, 0.83, 0.67) forwards;
}
@keyframes drop {
0% { transform: translateY(0); }
70% { transform: translateY(83px); } /* 超出目标 3px */
100% { transform: translateY(80px); }
}- 90% 处设超调比 70% 更明显,但容易显得“弹跳”,70% 是较自然的平衡点
- 不要用
steps()或百分比单位(如translateY(100%)),父容器高度变化时行为不可控 - 如果元素需要响应式,用
rem或vh替代px,但务必测试不同屏幕下的加速度观感是否一致
调试时最容易忽略的三件事
重力感动画成败不在参数多精细,而在三个执行细节是否到位:
- 所有涉及位移的属性必须走
transform,且加will-change: transform提前提示合成器(尤其 Safari) - 动画开始前确保元素已处于文档流中、有明确尺寸,否则
translateY可能因布局未就绪而偏移 - 移动端 touch 事件触发动画时,记得加
touch-action: manipulation防止延迟,否则“点击→掉落”会有明显滞后
参数可以抄,但这些细节不检查,再准的 cubic-bezier() 也会显得轻飘失重。


















