steps()是css animation-timing-function的一种,将动画切分为等距阶梯式跳变而非平滑过渡,专用于实现精灵图逐帧动画;8帧横向图需设steps(8, end)、background-position从0到-256px,并确保时长被帧数整除以避免卡顿。

什么是 steps(),它和逐帧动画有什么关系?
steps() 是 CSS animation-timing-function 的一种,它把一段动画「切片」成固定数量的等距阶梯——不是平滑过渡,而是一格一格跳变。做像素风精灵图(sprite sheet)动画时,你不需要缓动,只需要让背景位置在每一帧精准停住、停留固定时间,steps() 就是干这个的。
关键点:帧数 = steps(N) 的参数 N,但要注意方向:steps(N, start) 从第 0 帧开始跳,steps(N, end)(默认)从第 1 帧开始跳——多数 sprite 动画用 end 更直观。
怎么写一个 8 帧横向精灵图的逐帧动画?
假设你有一张横向排列的 8 帧 sprite 图,每帧宽 32px,总宽 256px;容器尺寸为 32px × 32px,且只显示单帧:
div.sprite {
width: 32px;
height: 32px;
background-image: url('walk.png');
background-size: 256px 32px; /* 横向拉伸适配 */
animation: walk 0.8s steps(8, end) infinite;
}
<p>@keyframes walk {
0% { background-position: 0 0; }
100% { background-position: -256px 0; }
}</p>
说明:
-
steps(8, end)表示将 0.8s 分成 8 个等长区间(每帧 0.1s),并在每个区间**结束时**跳到下一帧 -
background-position从0到-256px,是因为第 8 帧左边缘在 -224px(即 -32×7),但动画终点设为 -256px 才能确保最后一帧完整停留一个周期 - 若设为
steps(8, start),第一帧会在 0s 瞬间跳走,导致首帧不可见
为什么动画卡顿、漏帧或循环错位?常见坑有哪些?
这些问题几乎都源于 timing function 和关键帧范围不匹配:
- 用
steps(8)却只写了0% { bp: 0 } → 100% { bp: -224px }:终点 -224px 对应第 8 帧左缘,但steps(8)实际需要覆盖 9 个位置(0 → -32 → -64 → … → -256),少一格就丢最后一帧 - 动画时长不能被帧数整除(如 0.7s / 8 帧 ≈ 0.0875s),浏览器会四舍五入调度,可能造成微卡顿;建议时长选能被帧数整除的值(如 0.8s、1.6s)
- 没设
background-repeat: no-repeat或background-size错误,导致 sprite 被缩放/重复,帧定位偏移 - 在高 DPR 屏幕上,若 sprite 图是 @1x 但未用
background-size校准,实际渲染像素错位,帧看起来模糊或半帧闪现
如何支持竖向排列、多行或非等宽帧的 sprite?
steps() 本身不关心布局方向,只管「跳多少次」,但 background-position 计算方式要变:
- 竖向 6 帧(每帧高 48px):动画从
0→-288px,用steps(6, end) - 4×4 网格共 16 帧:需用 JavaScript 或预处理器生成 16 个关键帧,或改用
animation-direction: normal+ 多段@keyframes链式控制;纯 CSS 的steps()只适合线性序列 - 非等宽帧(如像素动画含待机帧更长):
steps()不适用,必须放弃逐帧定时,改用@keyframes显式写出每帧的background-position和精确时间点(例如0%, 12.5% { bp: 0 } → 12.5%, 25% { bp: -32px })
真正难的从来不是写对 steps(8),而是 sprite 图的导出精度、CSS 单位与设备像素比的对齐、以及动画循环起点是否视觉无缝——这些地方一松懈,像素风就糊了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











