还记得一个月前财付通首页的那套动画吗?作为设计湿抑或程序猿,你有没为她的实现感到好奇?今天,我们就搭乘时空车,穿梭回去探个究竟吧。温馨提示:抓紧扶手哦~
从我们耳熟能详的童话故事入手,将“快捷”、“移动”、“安全”、“轻松”融入其中,寓情于景、寓教于乐,于无形中将财付通的品牌理念植入用户心中……
动画的进入效果,模仿的是立体贺卡的展开:基本背景先映入眼帘——>人物/近景、事物/远景从纸面上(画面的地面上)站立起来——>装饰物(文字)从另一空间出现(从屏幕上方坠落),如图:
其中,近景和远景的分开翻转,使立体感、层次感更分明,动画更饱满;时间顺序上,由远及近、由上到下,更贴近立体贺卡的感觉。
3D动画没有立体效果,像2D一样2B?有没有遇到过?你是怎么处理的?
开始讨论这个问题之前,我们先来了解一下基本动画——旋转。css3中的旋转有绕x轴、绕y轴和绕z轴旋转三种,坐标系如下图:
如果非要举个例子的话,体操运动员的单杠运动是绕x轴旋转:
jolin姐姐跳钢管舞是绕y轴旋转:
旋转飞刀的特技表演是绕z轴旋转:
由坐标系和图图可以看出,z轴是垂直于屏幕的,绕z轴旋转是在平行于屏幕的平面上旋转,因此旋转是2D的,旋转的属性是rotate();而绕x轴和y轴旋转是在垂直于屏幕的平面上旋转,是3D的,旋转的属性分别是rotateX()和rotateY()。
回到主题,我们动画中的前/后景翻转,实则是绕着x轴旋转90度。初步测试时,设好了旋转的属性和角度值,前/后景可以翻转了,但是却毫无立体感可言,不是从地面上“翻”起来,而像是从地面上“冒”出来似的,纵深方向上(即z轴方向)没有距离感。查阅资料后发现,原来3D效果是要设置透视参数的(没有透视,不成3D),常用的两个透视属性如下:
perspective:设置镜头到元素平面的距离(所有元素默认都放置在z=0的平面——即屏幕上)。比如perspective(500px)表示,镜头距离元素表面的位置是500像素。此时你看该元素,就好像你的眼睛距离该元素500像素远时看到的效果。示例如下:
原图:
不设透视时,元素绕y轴旋转45度:
透视距离设为500px时,元素绕y轴旋转45度:
有图有真相,这下明白了吧?不过,透视距离到底设多少才合适呢?
各位看官想想,既然镜头模拟的是我们的眼睛,那么,我们的眼睛距屏幕有多远,是不是透视距离就该为多少呢?答案是肯定的。鉴于目前主流的屏幕分辨率在1680*1050上下,而眼睛距离显示器的距离大约为1.2个显示器的宽度,故透视距离大致应设为1680px*1.2=2016px≈2000px。
perspective-origin:规定镜头在平面上的位置,默认放在元素的中心。
示例如下:
在我们的动画中,透视距离perspective设的是2000px;因视线垂直屏幕即可,故不需设置perspective-origin。
Safari下图片会透过图片穿过来,就像电影里,鬼可以穿过人的身体一样。难道,真的见鬼了?!!
版本首次发布后,发现Safari下前景会穿过后景翻转起来(线上存在几个小时,有同学可能还记得当时的现象)。检查动画的实现方式,没有问题;检查图片的z-index,也正常;而且同为Webkit内核,Chrome下完全正常,只有Safari有此问题(我了个去,Safari是不是Webkit家族的呀,血统不正啊)。理论很丰满,展现很骨感;同内核不同表现;唉~
阿拉水平有限,没有找到根本原因,最终采取了一种伪方法来解决:
将后景图在z轴方向上向着屏幕内平移一定距离,使前景和后景图贴在地面上时不会有叠在一起的部分,简单示意如下:
原图:
平移示意图:
平移后前后景是不会交叠在一起了,但后景图片变小了(沿着z轴向屏幕内,渐行渐远,渐行渐小……),需把它恢复正常大小才行啊,肿么办?缩放属性scale()。平移后图片缩小至原来的多少分之一,我们就把它通过scale属性再放大多少倍。
用代码说话:transform:translateZ(-350px) scale(1.17,1.17);
这样,前后景图贴在地面上时不会交叠,翻转时自然就不会穿透了。
元素移动的动画怎么实现,如果不流畅怎么办?用飘柔吗?
动画中实现元素的移动,通常有两种方法,一种就是我们熟知的绝对定位,即将要移动的元素绝对定位,然后通过top/bottom/left/right值来控制元素的动态位置;另一种是css3动画中专有的移动属性translate。
首页动画中文字的坠落和移出,最初是通过绝对定位后调整top值实现的,如坠落部分的动画代码:
后发现动作有些许的咔,调整时间和位移值后依然无效,换用translate后流畅了许多:
备注:已为元素设置默认状态:{ position:absolute;top:-600px; }
关于定位(top等)和位移(translate),就我目前的经验来说,translate在流畅度方面要好些,而且,移动的速度越慢,translate在流畅度方面的优势就越明显。但是,Firefox对translate的支持不是很好,某些速度下会像流星一样拖着长长的尾巴。So,究竟何去何从,还请各位具体问题具体分析,测试后再行定夺。
动画隐藏后再显示,Firefox和IE10下不能触发重播动画,点解?
如大家所见,我们的动画是4幅轮播的形式,当前播放的只有1幅,对于当前没有播到的动画,需将其隐藏起来。如果是你,你会怎么隐藏?用我们惯用的hide (display:none;)吗,播放时再通过 show (display:block;)将其显示出来?这样可以吗?当然可以——理论上!实际上,Firefox和IE10下,若将节点hide后再show,是不能触发重播动画的。
好吧,退一步海阔天空,最终通过透明度来控制动画容器节点的显隐。
支持动画的浏览器有Chrome、Safari、Firefox和IE10,对于不支持动画的浏览器,采取差异化体验,仅将图片淡入淡出。
第一副图片的动画播放时,页面往往还在加载资源,这时动画就会出现不流畅的现象。怎么处理呢?先出背景,让banner有个可以看的画面,待首屏加载完毕后再开始播放动画。
为了实现动画,一张图片被切成了4~5张,4幅下来,将近20张,虽然图片压了又压,总大小也500k有余了。如果网速低的话,全部加载完毕菊花都转疼了,带着拯救菊花的愿景,我们开始折腾了:
除第一幅动画所需的图片外,其他动画所需图片延时2s加载。你可能会问,那会不会播放到某幅动画的时候,或者用户点了某幅动画对应的轮播按钮时,该动画所需资源还没加载到啊?恭喜你,问对了——会!如果这个时候该播的动画资源还没加载到,banner就要空白了(如下图),怎么办呢?
不怕,道高一尺,魔高一丈,哪里有问题,哪里就有解决方案:
为了优化体验,出现这种情况时,需让动画暂时停留在上一幅的状态,待相应动画的资源加载完毕后再切换。可问题是,css3中的动画播放完毕后,是会回到动画播放前的状态的,而非停留到动画最后一帧的状态。据前文“Firefox和IE10不能触发重播动画?!”部分所述,动画播放前整个动画容器是通过透明度隐藏的,是不可见的,那么,“让动画暂时停留在上一幅的状态”只能是YY了。
就这么放弃吗?不!绝不!动画特性不支持,我们还有伪方法:
将动画拆分成in、out两段将动画拆分成in、out两段,其中in包含两个状态:进入和停留,将in的时间设置得很长(通过帧控制使进入时间不变,只是停留的时间长了,如将in设为50s,其中进入0.5s,停留49.5s),out时长不变。若到了轮播切换(周期为10s)的时候,或者用户点击了某轮播按钮时,如果下一幅要播放的动画素材已加载完毕,则js将动画切换至out状态,否则继续停留,直至下一幅播放动画的素材加载完毕才切换。(有点滑动门的赶脚,不过是时间方面的,有木有!)
以背景淡入淡出为例,动画方面代码说话:
拆分前:
拆分后:
首页动画,基本是我第一次尝试使用css3动画,边学边做,边做边学,很多地方理解地还不是很透彻,文中如有错误,欢迎指正,如有更好的建议和方法,跪求交流。css3动画,想要入门很容易,但想要玩得转、玩得嗨、玩得随心所欲却很难。其中的透视原理、数学思想等等都是值得深度挖掘的。只有把它们弄懂弄通,才能信手拈来,随意排列组合,用有限的属性做出无限可能的效果。。