85

网易新闻《娱乐圈画传》H5的动画技巧

 6 years ago
source link: https://mp.weixin.qq.com/s/xScwM7Z3I7wXYmZg7y9ajg
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

网易新闻《娱乐圈画传》H5的动画技巧

Original shadow 无界社区mixlab 2017-12-29 09:35 Posted on

Image

今天看到一个非常喜欢的H5,又是网易出品的!于是,我忍不住去研究了他的实现方式,有3个值得我们学习的地方,分别是逐帧动画,多种变换叠加的css动画,还有最亮的:画中画动画的实现方式,下文将分享技术实现方式。

实验环境,采用chrome开发者工具:

Image

一、逐帧动画

Image

这个h5,几乎没有采用gif图片,大部分采用css的方式实现的逐帧动画。

比如上图,每一帧的尺寸是500px 1000px,共有8帧,存成雪碧图的形式。

CSS雪碧 即CSS Sprite,也有人叫它CSS精灵,是一种CSS图像合并技术,该方法是将小图标和背景图像合并到一张图片上,然后利用css的背景定位来显示需要显示的图片部分。好处是减少你的网站的HTTP请求数量。

重点在于这句代码 animation: people_ani 1s steps(1,end) infinite;

其他如下:

<div class="people"></div>

.people {    animation: people_ani 1s steps(1,end) infinite;    background: url(images/cover_people.png) no-repeat;    position: absolute;    left: 20px;    bottom: -4px;    width: 500px;    height: 1000px; }
@keyframes people_ani {    0%{background-position:0 0}    12.5%{background-position:-500px 0}    25%{background-position:-1000px 0}    37.5%{background-position:-1500px 0}    50%{background-position:0 -1000px}    62.5%{background-position:-500px -1000px}    75%{background-position:-1000px -1000px}    87.5%{background-position:-1500px -1000px}    100%{background-position:-2000px -1000px} }

二、多种变换叠加的动画

首页的海浪波动动画,在x轴跟y轴都同时运动,采用了伪元素的这种方法。

Image

x轴的变化写在元素本身,y轴的变化写在before里。

代码如下:

<div class="water1"></div>


.water1 {    position: absolute;    left: 470px;    top: 760px;    width: 350px;    height: 400px; } .water1 {    animation: water1 3.0s ease 1s infinite; } @keyframes water1{    0%{transform:translate(0,0)}    50%{transform:translate(-60px,0)}    100%{transform:translate(0,0)} } .water1:before {    content: "";    position: absolute;    left: 0;    top: 0;    width: 100%;    height: 100%;    background: url(images/sprite_v2.png) no-repeat 0 -690px; } .water1:before {    animation: water2 3.0s ease 2s infinite; }
@keyframes water2{    0{transform:translate(0,0)}    50%{transform:translate(0,-50px)}     00%{transform:translate(0,0)} }

三、动态部分与背景分离:
这种就不多说了,这样可以减少图片文件大小。

Image

四、画中画的实现:

整个h5最吸引人的就是画中画的动画形式,下图是前后2帧的图片:

Image

前后2帧的变化关系如下图所示:

Image

这里都是采用canvas逐帧绘制而成的,比css方案有个好处,就是同一时间绘制显示的内容,避免了采用css分别变换带来的不确定性。

我们尝试下,这里只选取了其中2帧作为演示。

html代码:

<canvas id="app" width="750" height="1206"></canvas>

<div class="collection">
   <img src="./cover_v2.jpg">
   <img src="./p1.jpg"">
   <img src="./p2.jpg">
</div>

canvas撑满屏幕,div class='collection'隐藏。

设一个初始化参数:
js代码:

    domList=document.querySelector('.collection').children;
   imgList= [{          link: "./cover_v2.jpg",          imgW: "750",          imgH: "1206"      }, {          link: "./p1.jpg",          imgW: "1875",          imgH: "3015",          areaW: "152",          areaH: "244",          areaL: "370",          areaT: "1068",          gif: "p1"      }, {          link: "./p2.jpg",          imgW: "1875",          imgH: "3015",          areaW: "556",          areaH: "894",          areaL: "1251",          areaT: "1050"      }];


   index=1;
   radio=1;
           imgNext ={          link: "./p2.jpg",          imgW: "1875",          imgH: "3015",          areaW: "556",          areaH: "894",          areaL: "1251",          areaT: "1050"      };    imgCur ={          link: "./p1.jpg",          imgW: "1875",          imgH: "3015",          areaW: "152",          areaH: "244",          areaL: "370",          areaT: "1068",          gif: "p1"      };
       //p2.jpg    img_oversize = domList[index + 1];
       //p1.jpg    img_minisize = domList[index];    

当长按start按钮时,开始绘制逐帧动画,是通过radio不断乘于一个缩放系数达到目的的。

radio=0.99*radio

重复这一过程的代码如下:

radio=0.99*radio
drawImgOversize(img_oversize, imgNext.imgW, imgNext.imgH, imgNext.areaW, imgNext.areaH, imgNext.areaL, imgNext.areaT, radio)

上面这个代码表示,把后面一帧逐渐缩小至手机屏幕,原理如下图:

Image

再把前面一帧,逐渐缩小,成为画中画,原理如下图:

Image
radio=0.99*radio
drawImgMinisize(img_minisize, imgCur.imgW, imgCur.imgH, imgNext.imgW, imgNext.imgH, imgNext.areaW, imgNext.areaH, imgNext.areaL, imgNext.areaT, radio)

为了实验方便,我把radio跟两个方法都拆开来了,实际使用的时候,只需调用一次radio=0.99*radio即可。

drawImgOversize与drawImgMinisize有兴趣再深入理解下哦,代码如下:

   function drawImgOversize(img, imgNextWidth,imgNextHeight,imgNextAreaWidth, imgNextAreaHeight, imgNextAreaL, imgNextAreaT, radio) {

var sx = imgNextAreaL - (imgNextAreaWidth / radio - imgNextAreaWidth) * (imgNextAreaL / (imgNextWidth - imgNextAreaWidth)),            sy = imgNextAreaT - (imgNextAreaHeight / radio - imgNextAreaHeight) * (imgNextAreaT / (imgNextHeight - imgNextAreaHeight)),            swidth = imgNextAreaWidth / radio,            sheight = imgNextAreaHeight / radio,            x = 0,            y = 0,            width = 750,            height = 1206;

var   c=document.querySelector('#app')
     var  ctx=c.getContext('2d');      ctx.drawImage(img, sx, sy, swidth, sheight, x, y, width, height);    };


   function drawImgMinisize(img, imgCurWidth, imgCurHeight, imgNextWidth, imgNextHeight, imgNextAreaW, imgNextAreaH, imgNextAreaL, imgNextAreaT, radio) {
       var  c=document.querySelector('#app')
       var  ctx=c.getContext('2d');
       var sx = 0,            sy = 0,            swidth = imgCurWidth,            sheight = imgCurHeight,            x = (imgNextAreaW / radio - imgNextAreaW) * (imgNextAreaL / (imgNextWidth - imgNextAreaW)) * radio * 750 / imgNextAreaW,            y = (imgNextAreaH / radio - imgNextAreaH) * (imgNextAreaT / (imgNextHeight - imgNextAreaH)) * radio * 1206 / imgNextAreaH,            width = 750 * radio,            height = 1206 * radio;      ctx.drawImage(img, sx, sy, swidth, sheight, x, y, width, height);    };

以上就是动画技术的核心内容,以供学习研究之用。

附上h5的地址:

http://ent.163.com/special/entphotos2017/

ps:

之前我也研究另外2个喜欢的h5的实现方式,比如:

全民刷军装背后的AI技术及简单实现
从网易《初心》H5里学到的一些

可以点击查阅。


码字不易,开启新的打赏方式:

Image

本公众号定期更新关于

设计师、程序员发挥创意

互相融合的指南、作品。

主要技术栈:

nodejs、react native、electron

Elasticsearch

Solidity

Keras

欢迎关注,转发~

欢迎长按二维码

关注本号

Image

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK