CSS 逐帧动画实现指南
逐帧动画(frame-by-frame animation)是一种通过快速连续显示一系列静态图像来创造运动效果的技术。以下是使用CSS实现逐帧动画的几种方法。
1. 使用 steps()
计时函数
这是实现逐帧动画最常用的方法,通过animation-timing-function
的steps()
函数实现。
.sprite {
width: 100px;
height: 100px;
background-image: url('sprite-sheet.png');
animation: play 1s steps(6) infinite;
}
@keyframes play {
from { background-position: 0 0; }
to { background-position: -600px 0; }
}
参数说明:
steps(6)
- 表示动画分为6步完成-600px
- 雪碧图总宽度(6帧 × 每帧100px)
2. 完整雪碧图动画示例
<!DOCTYPE html>
<html>
<head>
<style>
.character {
width: 64px;
height: 64px;
background-image: url('https://example.com/walk-cycle.png');
background-position: 0 0;
animation: walk 1s steps(8) infinite;
}
@keyframes walk {
from { background-position: 0 0; }
to { background-position: -512px 0; } /* 8帧 × 64px */
}
</style>
</head>
<body>
<div class="character"></div>
</body>
</html>
3. 多行雪碧图处理
对于包含多行动画的雪碧图:
.sprite {
width: 64px;
height: 64px;
background-image: url('multi-row-sprite.png');
animation: play 0.8s steps(8) infinite;
}
/* 行走动画 */
.walk {
animation-name: walk;
}
@keyframes walk {
from { background-position: 0 0; }
to { background-position: -512px 0; }
}
/* 跳跃动画 */
.jump {
animation-name: jump;
}
@keyframes jump {
from { background-position: 0 -64px; } /* 第二行 */
to { background-position: -512px -64px; }
}
4. 使用多个DOM元素实现逐帧动画
如果不使用雪碧图,可以通过切换多个元素的显示来实现:
<div class="frame-animation">
<img src="frame1.png" class="frame active">
<img src="frame2.png" class="frame">
<img src="frame3.png" class="frame">
<img src="frame4.png" class="frame">
</div>
.frame-animation {
position: relative;
width: 100px;
height: 100px;
}
.frame {
position: absolute;
top: 0;
left: 0;
opacity: 0;
animation: frameAnimation 1s infinite;
}
.frame.active {
opacity: 1;
}
@keyframes frameAnimation {
0%, 25% { opacity: 0; }
25.1%, 50% {
opacity: 1;
z-index: 1;
}
50.1%, 75% {
opacity: 0;
z-index: 0;
}
75.1%, 100% {
opacity: 1;
z-index: 1;
}
}
.frame:nth-child(1) { animation-delay: 0s; }
.frame:nth-child(2) { animation-delay: 0.25s; }
.frame:nth-child(3) { animation-delay: 0.5s; }
.frame:nth-child(4) { animation-delay: 0.75s; }
5. 使用CSS自定义属性控制动画帧
:root {
--frame-count: 8;
--frame-width: 64px;
}
.sprite {
width: var(--frame-width);
height: 64px;
background-image: url('sprite.png');
animation: play 1s steps(var(--frame-count)) infinite;
}
@keyframes play {
to {
background-position: calc(-1 * var(--frame-count) * var(--frame-width)) 0;
}
}
性能优化建议
使用will-change:
.sprite { will-change: background-position; }
减少复合操作:
- 优先使用
opacity
和transform
属性 - 避免在动画中改变
width
/height
等属性
- 优先使用
合理使用硬件加速:
.sprite { transform: translateZ(0); }
控制动画频率:
@media (prefers-reduced-motion: reduce) { .sprite { animation: none; } }
浏览器兼容性
- 现代浏览器都支持
steps()
函数 - IE10及以上支持,但可能需要前缀
- 对于更老的浏览器,可以使用JavaScript实现回退
高级技巧:与JavaScript结合
// 动态改变动画速度
const sprite = document.querySelector('.sprite');
sprite.style.animationDuration = '0.5s';
// 暂停/播放动画
function toggleAnimation() {
const animation = sprite.style.animationPlayState;
sprite.style.animationPlayState =
animation === 'paused' ? 'running' : 'paused';
}
// 切换不同动画
function changeAnimation(type) {
sprite.style.animationName = type;
}
逐帧动画是游戏开发和UI动效中常用的技术,合理使用可以创建出流畅的视觉效果,同时保持较好的性能表现。