纯CSS金币弹跳动画需分四段:下落→触底压缩→反弹→衰减停稳,用cubic-bezier控制物理感,配合will-change: transform防卡顿,animation-delay随机化增强真实感。

用 @keyframes 控制金币下落 + 弹跳轨迹
纯 CSS 实现金币掉落并弹起,核心是用 @keyframes 描述位移、缩放和旋转的组合变化。不能只靠 transform: translateY() 线性下落——那样没有物理感,也弹不起来。
关键在于把整个动画拆成「下落→触底压缩→反弹→衰减停稳」四段,每段用不同缓动函数(cubic-bezier)模拟惯性:
- 下落阶段用
cubic-bezier(0.22, 0.61, 0.36, 1)(稍带加速) - 触底瞬间加
scaleY(0.7)和微小rotateZ(3deg)模拟形变 - 第一次反弹用
cubic-bezier(0.34, 1.56, 0.64, 1)(强回弹) - 后续反弹高度逐次降低,用多个
transform关键帧叠加实现
示例片段:
@keyframes coin-fall-bounce {
0% { transform: translateY(-100px) scaleY(1); }
60% { transform: translateY(200px) scaleY(0.7) rotateZ(3deg); }
75% { transform: translateY(120px) scaleY(1.1); }
90% { transform: translateY(160px) scaleY(0.95); }
100% { transform: translateY(180px) scaleY(1); }
}
animation-timing-function 别全用 ease
默认 ease 在弹跳场景里会显得“软塌塌”,金币像掉进棉花里。真实弹跳需要明确的“顿挫感”:触底要快停,反弹要快起。
必须手动配 cubic-bezier,尤其注意两点:
立即学习“前端免费学习笔记(深入)”;
- 触底帧(60% 左右)的出点控制值要接近
0,比如cubic-bezier(..., 0.05),才能刹得住 - 反弹起点(75% 帧)的入点控制值要 >1,如
cubic-bezier(0.34, 1.56, ...),制造超调效果 - 别在单个
animation里混用多个timing-function——CSS 不支持;得靠多段关键帧+不同贝塞尔值来模拟
用 will-change: transform 防掉帧
金币数量一多(比如 5+ 个同时掉落),没优化的话 iOS Safari 和低端安卓机容易卡顿,表现为弹跳变慢、帧率骤降。
根本原因是浏览器没提前把元素提升为独立图层。解决方式很直接:
- 给金币元素加
will-change: transform(仅动画期间设,动画结束记得移除) - 确保金币有
transform: translateZ(0)或opacity: 0.99这类触发硬件加速的属性 - 避免在动画中同时改
top/left和transform,会强制重排
错误写法:animation: coin-fall-bounce 1.2s; top: 200px; → 触发 layout
正确写法:animation: coin-fall-bounce 1.2s; transform: translateY(200px);
批量生成金币时,animation-delay 要随机化
如果所有金币用相同 animation-delay,看起来就是整整齐齐往下掉,毫无随机感,也不像真实抛洒。
真正在项目里,得用 JS 动态设延迟(哪怕只是简单随机):
- 用
Math.random() * 0.5给每个金币加 0–500ms 延迟 - 别用
setTimeout手动 addClass——DOM 操作开销大,直接设内联style.animationDelay更轻量 - 注意:CSS 自定义属性(
--delay)在@keyframes里不能被计算,所以延迟必须走原生animation-delay
JS 示例:
coin.style.animationDelay = `${Math.random() * 0.5}s`;
动画最难调的其实是第二、第三次反弹的高度比例和时长——差 5% 就显得假。多数人卡在这儿,不是不会写 keyframes,而是没盯着 Chrome DevTools 的 animation 面板一帧帧拖动对比。










