逐帧动画是个啥呢??
先让我们看一下下面两个网站,上面那动画,唰唰唰,哗哗哗,啦啦啦的,看着心痒的我就忍不住F12了一下,然后发现都用到了逐帧动画。
简单来说就是利用一张动画分解的 sprite 图,通过 js 脚本改变图片的 css 属性或使用 css3 的 animation 属性来实现动画的效果。
实现
利用 css3-animation 来制作逐帧动画
首先看一下对 animation 属性各个浏览器的支持情况,IE 10+、Firefox 以及 Opera 支持 animation 属性。
Safari 和 Chrome 支持替代的 -webkit-animation 属性。(IE9以下不支持)
animation 其他几个动画属性就不多说了,这次要用到的是 animation-timing-function 里的steps()阶段函数。
animation-timing-function: ease | linear | ease-in | ease-out | ease-in-out | step-start | step-end | steps(
<integer>
[, [ start | end ] ]?) | cubic-bezier(<number>
,<number>
,<number>
,<number>
)
取值:
linear:线性过渡。等同于贝塞尔曲线(0.0, 0.0, 1.0, 1.0)
ease:平滑过渡。等同于贝塞尔曲线(0.25, 0.1, 0.25, 1.0)
ease-in:由慢到快。等同于贝塞尔曲线(0.42, 0, 1.0, 1.0)
ease-out:由快到慢。等同于贝塞尔曲线(0, 0, 0.58, 1.0)
ease-in-out:由慢到快再到慢。等同于贝塞尔曲线(0.42, 0, 0.58, 1.0)
step-start:等同于 steps(1, start)
step-end:等同于 steps(1, end)
steps(<integer>
[, [ start | end ] ]?):接受两个参数的步进函数。第一个参数必须为正整数,指定函数的步数。第二个参数取值可以是start或end,指定每一步的值发生变化的时间点。第二个参数是可选的,默认值为end。
cubic-bezier(<number>
, <number>
, <number>
, <number>
):特定的贝塞尔曲线类型,4个数值需在[0, 1]区间内
所以这个 steps() 函数是个啥呢,下图是W3C对这个函数的图解
大概意思呢就是这个函数可以将动画分成 n 等分,start 和end 决定动画执行是从前还是从后。
例如我们有上面这么一张逐帧动画图,因为动画是从左往右,所以先写一个关键帧 keyframes 名字叫 sprite-animate-go,背景起始位置从 0% 到 100%,具体代码如下:
.go {
background: url(http://www.gaoquanquan.com/wp-content/uploads/2016/04/go.png) no-repeat;
width: 50px;
height: 65px;
margin: 0 auto;
animation: sprite-animate-go 1.5s steps(50) infinite;
-webkit-animation: sprite-animate-go 1.5s steps(50) infinite;
}
@keyframes sprite-animate-go {
from {
background-position: 0%;
}
to {
background-position: 100%;
}
}
@-webkit-keyframes sprite-animate-go {
from {
background-position: 0%;
}
to {
background-position: 100%;
}
}
效果如下:
使用 js 脚本操作 css 属性
上面两个网站都是用的脚本实现的,因为使用 js 可以兼容大部分浏览器,是最保险的方法。思路就很简单了,帧图片外面加个固定大小的 div,overflow: hidden, 然后用js不断改变帧图片的 translate 值。
代码如下:
<div class="intro-container">
<img src="http://www.gaoquanquan.com/wp-content/uploads/2016/04/go.png">
</div>
.intro-container {
width: 50px;
height: 65px;
overflow: hidden;
}
window.onload = function(){
var introSprite = $(".intro-container");
spriteAnim(introSprite, 25, 59, 33, 2, false);
}
function spriteAnim(container, fps, frames, col, row, loop) {
var intro = container.find('.intro');
var width = container.width();
var height = container.height();
var frame = 1;
var x = y = 0;
intro.css({transform: 'translate3d(0, 0, 0)', '-webkit-transform': '-webkit-translate3d(0, 0, 0)'});
setTimeout(function() {
playSpriteAnim(intro, fps, width, height, frames, col, row, frame, x, y, loop);
}, 1000/fps);
}
function playSpriteAnim(intro, fps, width, height, frames, col, row, frame, x, y, loop) {
x++;
if (x >= col) {
x = 0;
y++;
}
var bgX = '-'+(x*width)+'px';
var bgY = '-'+(y*height)+'px';
intro.css({transform: 'translate3d('+bgX+', '+bgY+', 0)', '-webkit-transform': '-webkit-translate3d('+bgX+', '+bgY+', 0)'});
frame++;
if (frame >= frames) {
if (loop) {
frame = 1;
x = y = 0;
} else {
intro.closest('.intro-container').trigger('end')
return;
}
}
setTimeout(function() {
playSpriteAnim(intro, fps, width, height, frames, col, row, frame, x, y, loop);
}, 1000/fps);
}
思考 🤔
PS,那么问题来了,
1.有了gif干嘛还要费劲用逐帧动画?
区别大概在于可以控制逐帧动画的快慢和暂停,而且gif动画不够清晰,有些时候达不到我们的要求。
2.怎么得到一张逐帧图片嘞?
确切的说应该是从AE导出的序列帧图组怎么合成一张图嘞?这个问题好像不是应该我考虑的,但你们不想知道吗?不想吗?想吗?吗?我可是想好久呢,就是
美图秀秀啊
虽然一次最多拼30张,但真的挺好用的…