转载

聊聊 618 作战指挥室大屏动画

如火六月, 年度618给我们送来一缕清风,这是个与“双11”遥相呼应的又一大全民网购狂欢节(PS:你剁手了吗?) ,秉承着只为品质生活的宗旨,带我们进入前所未有的品质狂欢盛宴。618期间战场硝烟弥漫,全体JDers火力全开!作为研发MM的我,也接到了618作战指挥室大屏项目。而今,激情high战的红六月已渐渐远去,那么随我一起来浅解析一下本次618作战指挥室大屏动画吧!

说到动画,不知道大家还记不记得手翻书。我们小时候曾经玩过的(甚至画过的)这种通过快速翻页产生动画效果的小册子。

聊聊 618 作战指挥室大屏动画

先让我们先回味一下手翻书动画。

1 、GIF动画

试想如果把存于一个文件中的多幅图像数据逐幅读出并显示到屏幕上,是不是就可构成一种最简单的动画。我们熟知的GIF图实现原理就类似于这样, 当我们把上面的GIF图在PS中打开时,就可以看到时间轴上很多帧图片。

聊聊 618 作战指挥室大屏动画

下面是页面全景图版块文字闪烁效果。

聊聊 618 作战指挥室大屏动画

接到这个需求效果,我们是不是最先想到用GIF图实现,因为它成本低,使用方便,只需要设计设计好直接使用就可以。

但是我们却一时忽略GIF图有它的短板:

  • 我们无法在css层面上修改一些参数,不能直接控制持续时间、循环次数、是否暂停,GIF一旦生成,参数就固定定了。可以执行比较差、对于调试很不方便。
  • 所有能使用的颜色数量呗限制在256色。
  • 不具备Alpha透明的特性,即使做成透明的,毛边锯齿也会让我们抛弃它。

因为我们这次的页面背景是流转的云朵和星空,为了不遮挡背景效果,所以我们放弃利用GIF去实现。

这时你可能会说,那用APNG呀! 确实,在实现的时候我们也考虑过,但最终我们确认本次大屏幕使用Chrome浏览器,而APNG并没有得到该浏览器支持。

2 、逐帧动画

GIF图和APNG的路都被我们断掉,这时让我们想到了和GIF有着相同共性的CSS逐帧动画。说到逐帧动画,可能有些人会问,什么是逐帧动画呢?

引用百度百科的介绍:

“逐帧动画是一种常见的动画形式(Frame By Frame),其原理是在“连续的关键帧”中分解动画动作,也就是在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成动画。”

那如何实现逐帧动画呢?

其实实现逐帧动画的秘籍是使用steps() 这个调速函数。steps()这个调速函数会根据你设置的步数量,把动画分成多个帧,让整个动画在帧与帧之间硬切,之前我们对于这种硬切效果是避之不及的,然而,正是因为这种硬切,完美的实现了我们想要的效果。究其原理就是使用一张含有多帧静态画面的精灵图片,通过切换 background-position使其变为连续的动画。对于这一技巧,我们要感谢 Simurai , 在他的个人网站中提到使用steps()实现这种精灵动画。

说完它的实现原理,大家是不是更希望知道如何使用它呢?

首先我们要知道,steps(number_of_steps, direction)这个调速函数接受两个参数:

第一个参数:动画每两个帧之间的间隔数。这个参数并不指代整个动画的间隔,使用的时候应该注意。

第二个参数:可以接收start或是end(默认的),这个参数可以指定动画在每个循环周期的什么位置发生帧的切换动作。

接下来,我们再借助 W3C 官网对steps()函数的剖析图来理解一下。

聊聊 618 作战指挥室大屏动画

看完这张图我们是不是豁然开朗了呢!了解完它的参数,下面让我们来看一下,本次大屏的文字闪动效果,我们是如何实现的:

第一种:

.flicker-title{
    width: 400px;
    height: 50px;
    animation: flicker 1s infinitesteps(11, end);
    background: url(flicker.png) no-repeat 0 0;
}
@keyframes flicker {
    100%{ background-position: -4400px 0px;}
}

第二种:

.flicker-title{
    width: 400px;
    height: 50px;
    animation: flicker 1s infinitesteps(1, end);
    background: url(flicker.png) no-repeat 0 0 ;
}
@keyframes flicker {
    0%{ background-position: 0px 0px;}
    ...
    45.5%{ background-position: -2000px 0px;}
    ...
    100%{ background-position: -4400px 0px;}
}

这里我们还可以使用step-start 和step-end 替换 steps(1, start) 和steps(1, end)。顺便安利一个 帧数计算器工具 。

2 、补间动画

聊完逐帧动画,现在我们来说补间动画。不同于逐帧动画在两个帧之间的硬切,补间动画需要在两个帧之间进行插值运算,从而产生平滑的过渡效果。

好的动画需要我们呈现真实的效果,如何让我们制作的动画感觉更真实,无疑成为我们写动画需要特别关注的点,动画看似简单,其实是个细节活。生硬的动过效果,不仅不会给我们页面锦上添花,反而会让用户更加无法直视。如何想要动画真实,我们首先需要让它遵循自然的规律。

聊聊 618 作战指挥室大屏动画

如图,当我们把一个小球,自由释放的时候,它并不是匀速下落的,而是会越来越快,碰到地板也不会立即停止,而是反弹几次,最终静止在地板上。记得初中的物理课本有论述过,对任何物体,无论是运动还是静止,无论是运动状态改变还是不变,物体都具有惯性。小球的下落就是遵循了这种自然规律。

下面我们来看大屏一个流量汇入的动画效果,看到这个动画,大家是不是很想知道它是如何实现的。

聊聊 618 作战指挥室大屏动画

下面我们就来聊聊他的实现过程。

其实,接到动画的时候我们切忌不要立即去码代码,而是应该先构思一下动画的布局,和设计师沟通好每节动画的效果,然后把动画拆解开来,这样不仅可以让我们思路更清晰,而且也可以减少后期修改的次数。

我们知道补间动画主要是通过animation/transition结合 transfrom/opacity 实现的。如果我们在制作的时候没有思路,也许 Animate.css 这个网站可以帮助你。

下面我们拿上面动画一个分支举例:

聊聊 618 作战指挥室大屏动画

从图中我们可以获取X轴的偏移量、Y轴的偏移量和旋转球形路径的直径R。知道元素路径的直径R之后,我们就可以设置旋转元素的基点位置:transform-origin: 50% R/2 。然后我们通过改变光点的translateX()、translateY()、rotateZ()等属性来改变光点运动轨迹,在轨迹终点指定位置修改opacity的透明值,达到我们想要的效果。

代码如下:

@keyframes globulePath {
    0%{ transform: translateX(0) translateY(220px) rotate(0.5turn); opacity: 1;}
    25%{ transform: translateX(182px) translateY(220px) rotate(0.5turn); opacity: 1;}
    50%{ transform: translateX(182px) translateY(220px) rotate(0.73turn); opacity: 1;}
    90%{ transform: translateX(182px) translateY(508px) rotate(0.73turn); opacity: 1;}
    100%{ transform: translateX(182px) translateY(580px) rotate(0.73turn); opacity: 0.3;}
}
.globule{
    height:40px;
    width: 40px;
    transform-origin: 50% -90px;
    animation: globulePath 6s infinitelinear;
    background: url(i/globule.png) no-repeatcentertop;
}

动画性能

动画不仅只是开发完就完事的,性能也是我们需要注意的点。我们知道,页面在渲染的时候Layout和Paint两个环节是最影响性能的, 所以我们应该注意用 transform里面的属性来替换定位(top、left、right、bottom),和宽高(width、height), opacity属性来替换display等。这里推荐一个给力的网站 CSS TRIGGERS ,这里详细的列出了我们使用的CSS属性在修改后是否会触发Layout和Paint。

我们也可以适当开启GPU硬件加速模式,其实算是一个hack,给元素设置transfrom: translate3d(0, 0, 0)或是transfrom: translateZ(0),本身这两个属性是为了渲染3D效果,但我们把值都设置为0之后,并没有真正使用3D效果,浏览器却因此开启了GPU硬件加速模式,但是这种所谓硬件加速也就是就是创建了一个被传递到GPU处理的层,强制使用hack方式创建layer。Chrome提供一个更好的方式,使用will-change属性,它可以提前通知浏览器我们要对元素做什么动画,这样浏览器可以提前准备合适的优化设置,我们设置will-change: transform, opacity; 这种方式要比之前hack要好一些。

最后

本页面放在618作战指挥室,页面分辨率高达10800×1620px,很多动画我们PC端不能完整查看,所以本文只是抽出其中几个小动画来讲解动画的相关知识和开发思路。如有问题,还请大家指正。

原文  http://jdc.jd.com/archives/1801
正文到此结束
Loading...