cubic-bezier() 是纯 css 实现真实弹跳动效的唯一可行路径,因其能通过自定义控制点使速度中途反向(y>1 或 y

为什么 cubic-bezier() 是弹跳动效的唯一可行路径
纯 CSS 实现真实弹跳(bouncing),不能靠 animation-timing-function: ease-out 或重复 keyframes 模拟——它只是减速,没有回弹、过冲、衰减。真正有物理感的弹跳必须用自定义贝塞尔曲线,因为只有 cubic-bezier() 能让速度在动画中途“反向”(y 值 > 1 或
浏览器原生支持的 timing function 中,只有 cubic-bezier() 允许控制点超出 [0,1] 范围(如 cubic-bezier(0.2, 0.8, 0.4, 1.4)),这是实现“冲过头再弹回”的关键。
常见错误:直接抄网上“弹跳贝塞尔值”却不验证是否符合 CSS 规范——CSS 要求 x1/x2 ∈ [0,1],但 y1/y2 可以任意(现代浏览器都支持)。若误把 y1 写成 1.8 但 x1 写成 -0.1,会直接被忽略并退化为 ease。
怎么写出一个可用的弹跳 cubic-bezier() 曲线
别从头手调四个参数。用工具辅助生成,再微调。核心逻辑是:前半段快速下落 → 底部猛烈过冲 → 多次小幅回弹 → 最终静止。
立即学习“前端免费学习笔记(深入)”;
- 推荐起始模板:
cubic-bezier(0.34, 1.56, 0.64, 1)(基础单次弹跳) - 要更“松软”:降低 y1(如 1.2),提高 y2(如 1.1)→ 回弹更缓
- 要更“硬脆”:提高 y1(如 1.8),降低 y2(如 0.8)→ 首次过冲更猛,后续衰减快
- 想加第二次小弹跳:把 y2 设为略大于 1(如 1.05),让曲线在末尾轻微上扬
实操建议:在 Chrome DevTools 的 animation 面板里实时拖拽贝塞尔手柄,观察曲线形状和预览效果;不要只看数值。
transform: translateY() + cubic-bezier() 的典型用法与坑
弹跳动效几乎总是作用于 transform,而非 top 或 margin——前者触发合成层,性能好;后者触发布局重排,一卡就废。
常见错误现象:animation 播放一次后不重置位置,导致第二次点击从错误起点开始弹。
- 务必在动画结束时显式归位,例如用
transform: translateY(0)写在@keyframes的to或 100% - 如果用
animation-fill-mode: forwards,确保to状态是最终静止态(不是弹跳中途某帧) - 移动端要注意:iOS Safari 对超范围 y 值(如 y1=2.1)兼容性略差,稳妥起见 y1 控制在 ≤1.9,y2 ≥0.7
- 避免和
transition混用:同时存在时,transition会覆盖animation的 timing function
多段弹跳(比如三次回弹)还能用纯 CSS 吗
能,但别写三段 @keyframes 硬凑。复杂弹跳应拆解为多个连续动画,用 animation-delay 错开,并逐段调整 cubic-bezier() 参数模拟衰减。
示例思路(单次点击触发三段弹跳):
button:hover {
animation:
bounce-1 0.6s cubic-bezier(0.34, 1.56, 0.64, 1),
bounce-2 0.4s cubic-bezier(0.22, 0.8, 0.56, 1.2) 0.6s,
bounce-3 0.25s cubic-bezier(0.18, 0.7, 0.42, 1.05) 1.0s;
}
关键点:
- 每段动画的
transform起始值必须承接上一段的结束值(靠animation-fill-mode: forwards保证) - 第二、三段的
cubic-bezier()y1 逐级降低(1.2 → 1.05),体现能量衰减 - 总时长 = 各段时长 + 延迟之和,别漏算
真正难的不是写出来,而是让每次回弹的幅度、节奏看起来自然——这取决于你调参时有没有盯着真实弹簧或篮球录像看两分钟。










