用steps()实现小球碰撞动画是因为其能产生离散帧感,如steps(4,end)将动画均分为4步、每步结束才跳变位置,而linear会匀速过渡失去顿挫感;需确保keyframes百分比节点数比step数多1且末帧停留,同时注意overflow:hidden和transform-origin等细节。

为什么用 steps() 而不是 ease 或 linear
因为小球碰撞动画需要「离散帧感」:比如小球从左到右、突然反弹、再停顿一帧、再弹回——这种“卡顿式”运动不是平滑过渡,而是分步跳跃。steps(4, end) 表示把整个动画时长均分为 4 步,每步结束时才跳到下一位置;若用 linear,小球会匀速划过中间所有点,失去碰撞的顿挫感和物理反馈。
-
steps(1, start):整段动画只在开始瞬间跳到终点(适合开关类切换) -
steps(6, end):更适合模拟 6 帧碰撞循环(如:左→中→右→中→左→停) - 注意:
end表示每步在时间区间的末尾生效,start则在开头生效,视觉差异明显,建议统一用end避免首帧闪动
如何用 steps() 配合 @keyframes 实现小球左右碰撞
关键不在位移本身,而在「关键帧设计必须匹配 step 数量」。例如设 animation: bounce 1s steps(5, end),那么 @keyframes bounce 就得定义 6 个状态(0%, 20%, 40%, 60%, 80%, 100%),让每步恰好对应一次位置切换。
```css
@keyframes bounce {
0% { transform: translateX(0); }
20% { transform: translateX(100px); }
40% { transform: translateX(200px); }
60% { transform: translateX(100px); }
80% { transform: translateX(0); }
100% { transform: translateX(0); }
}
.ball {
animation: bounce 1s steps(5, end) infinite;
}
```
- step 数 = 关键帧区间数(即 100% / 百分比间隔),不是关键帧个数
- 最后一帧设为重复停留(如上例 80%→100% 都在
translateX(0)),可模拟碰撞后静止缓冲 - 避免在
steps()动画中混用transform: scale()连续变化,否则顿挫感会被柔化破坏
小球碰撞动画里最容易被忽略的两个细节
一是容器 overflow: hidden 缺失——小球在 step 跳变过程中可能短暂超出父容器边界,导致边缘闪烁或布局抖动;二是未重置 transform-origin,当小球同时做旋转+位移时,steps() 会优先采样 transform 矩阵整体,造成位移偏移。
- 务必给小球父容器加
overflow: hidden - 如果小球是圆形(
border-radius: 50%),确保width和height相等,否则translateX在不同缩放下步长感知不一致 - 不要在同一个
transform声明里混写translateX()和rotate()并期望steps()精确控制其中一项——浏览器按矩阵合成处理,结果不可控
兼容性与性能提醒
steps() 在所有现代浏览器中支持良好(Chrome 23+、Firefox 16+、Safari 7+),但 IE10 及以下完全不支持,且无 polyfill 可补。移动端 iOS Safari 对 steps() + transform 组合偶发掉帧,尤其在低电量模式下。
- 如需兼容 IE,只能降级为 JavaScript 定时器 + class 切换(每 200ms 切一个位置 class)
- 避免在
steps()动画中驱动大量小球(>10 个),CSS 动画虽硬件加速,但 step 模式会强制 Layout → Paint 流程更频繁 - 真要高性能大批量,改用 Canvas 或 WebGL;CSS
steps()本质是「优雅的有限状态机」,不是通用动画引擎
实际做出来才发现,最难的不是写出那几行 @keyframes,而是想清楚「这个碰撞到底该拆成几步」——步太少像抽搐,步太多就滑了。而每一步的位置值,得手算或靠调试反复对齐视觉节奏。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











