当前位置: 首页 > Web前端 > HTML5

前端动画实现与原理分析

时间:2023-04-05 12:53:38 HTML5

背景今天的前端是一个涉及面很广的职业。作为前端,我们不仅要开发管理系统和数据平台,还要应对年报开发、节日活动等场景。不仅要会增删改查、写表单,还要有动画、H5游戏的开发能力。能够做出炫酷的动画效果,也是前端特有的成就感。因此,我们从动画的实现方法入手,了解浏览器的渲染,以及如何提高动画的性能。先来看两个H5案例:【一镜到底】<->手机扫一扫体验【年报】【其他H5优秀案例】https://www.h5anli.com第一部分常见动画实现方式1.1gif实现定义:GIF文件的数据是一种基于LZW算法的连续色调无损压缩格式。gif格式的特点是一个gif文件可以存储多张彩色图片。当数据被一个一个读出并显示在屏幕上时,就可以组成一个简单的动画。最多支持256种颜色。由于这个特性,GIF更适合颜色较少的图片,如页面卡通图标、logo等。使用:![file](/img/bVcZPme)优点:1、制作成本很低;2、相容性好;3、开发使用方便。缺点:1、画质方面:颜色支持少,图像毛刺严重;2、在交互方面:动画的播放和暂停无法控制,没有灵活性;3.大小方面:由于无损压缩,每一帧都被完整保存。导致大文件。1.2css3补帧动画1.2.1transition过渡动画用法:.box{border:1pxsolidblack;宽度:100px;高度:100px;背景色:#0000ff;过渡:宽度2s,高度2s,背景色2s,变换2s;}.box:hover{background-color:#ffcccc;宽度:200px;高度:200px;transform:rotate(180deg);}场景:常与:hover、:active等伪类配合使用,实现相应的动画效果。1.2.2动画关键帧动画用法:.bounce1{left:-40px;动画:bouncy11.5sinfinite;}.bounce2{left:0;动画:bouncy21.5sinfinite;}.bounce3{left:40px;动画:bouncy31.5sinfinite;}@keyframesbouncy1{0%{transform:translate(0px,0px)rotate(0deg);}50%{transform:translate(0px,0px)rotate(180deg);}100%{transform:translate(40px,0px)rotate(-180deg);}}场景:例如:加载显示,代码如上。优点:1、不需要每一帧都记录,通过关键帧设置方便开发;2.实现简单,通常UI直接给css文件即可,前端只需要导入【移动端注意屏幕适配】。缺点:1.css无法与动画交互,无法获知当前动画执行阶段;2.转场:需要触发,不能自动播放;3.动画兼容性需要加前缀,导致代码体积翻倍;4.对于复杂的动画导入的css文件实现过大,影响页面的渲染树生成,从而阻塞渲染。例如,要达到摇钱树的效果,如果css文件达到100kb,就必须采用一些必要的压缩方法来减小文件大小。1.3js逐帧动画JS动画的原理是通过setTimeout或requestAnimationFrame方法绘制动画帧,从而动态改变网页中图形的显示属性(如DOM样式、canvas位图数据、SVG对象属性等)等),进而达到动画的目的。demo1:--------js实现一个从左到右的正方形移动动画------setTimeout实现constelement2=document.getElementById('raf2');constbtn2=document.getElementById('btn2');leti=0;lettimerId;functionmove(){element2.style.marginLeft=i+'px'timerId=setTimeout(move,0)i++;如果(i>200){clearTimeout(timerId)}}btn2。addEventListener('click',function(){move()})requestAnimationFrameimplementationconstelement=document.getElementById('raf');constbtn1=document.getElementById('btn1');letr=0;letrafId;functionstep(){element1.style.marginLeft=r+'px';rafId=window.requestAnimationFrame(step);r++;if(r>200){//两秒后停止动画cancelAnimationFrame(rafId);}}btn1。addEventListener('click',function(){step();})可以看出实现方法是控制dom的margin-left样式,进行动画。问题1.1:从demo1可以看出setTimeout的执行速度非常快。为什么是这样?请继续阅读~Part2浏览器是如何渲染和渲染动画的2.1浏览器的框架原理问题2:url输入到一个页面并显示时,经过了哪些过程?这里我们忽略HTTP请求静态文件之前的步骤,重点关注浏览器是如何渲染帧的,从而了解浏览器是如何渲染动画的。借助chrome-performance【执行raf.html】,我们还可以在上图中看到不同阶段的performance中的注解。??注意:并非每一帧都将始终由管道的每个部分处理。事实上,无论是使用JavaScript、CSS还是网络动画,在实现视觉变化时,通常有3种方式将管线帧运行到指定帧:【以下截图均以时间轴为主轴绘制】——当一些修改制作完成后,会触发layout的属性,也会导致下面的更新。修改时只是改变了paint的属性,不会重新布局。如果更改一些不涉及布局或重绘的数据,可以直接进行复合渲染。像CSS属性,可以查询这个网站,看看哪些属性会导致什么样的framepipeline:https://csstriggers.com/例如:transform变换,不会触发布局和绘制的变化,所以用在这个时间,直接进入第三状态是一个很好的优化方式。合成后直接进入Composite阶段。问题3:控制台显示了requestAnimationFrame(rAF)的执行,那么这个rAF的执行和浏览器框架有什么关系呢?我们往下看。2.2requestAnimationFrame的执行我们还是运行demo1的代码:可以看到rAF是在layout和paint之前执行的,rAF每帧只执行一次,调用回调函数执行动画。从rAF的执行时序可以看出,setTimeout的执行时序与rAF不同。通过不同方式捕捉方块移动动画的表现,我们可以看到:setTimeoutunitframescreenshot:rAFunitframescreenshot:两者对比,我们可以看到在16.7ms内,seTimeout被执行了4次,导致了这个差异此时设置的marginLeft与上次渲染前的marginLeft之间必须大于1px。而raf可以看到marginLeft和上次渲染前的marginLeft的差等于1px。从rAf的性能可以看出setTimeout的性能会差一点。如果JS执行时间过长,该画一帧就画不出来,会延迟到下一帧执行。导致动画滞后。【这里可以跳到性能问题的第三部分,直观的看到卡顿就知道了】可以得出结论:1.setTimeout的时间不准确,因为它的执行依赖于执行时间的主线程。2.如果定时器频率高于浏览器的刷新率,即使执行代码,浏览器不刷新,也没有显示,出现掉帧,不流畅。而raf解决了setTimeout动画带来的问题:1.当浏览器刷新屏幕时自动执行,无需设置时间间隔。和setTimeout一样,在n毫秒后执行,但是这个n毫秒自动设置为浏览器刷新频率,浏览器刷新一次,执行一次,不需要手动设置;浏览器不刷新则不执行,不存在排队丢帧。2.高频函数节流对于resize和scroll高频触发事件,使用requestAnimationFrame可以保证函数在每个绘制区间只执行一次,节省函数执行的开销。如果使用setTimeout和setInterval,在浏览器刷新间隔期间可能会有无用的回调函数调用,浪费资源。第三部分性能分析与高效动画3.1性能分析通过chrome-performance可以看到整体的fps和GPU情况,也可以逐帧分析影响脚本\渲染\绘画时间的因素,从而有针对性地提高动画性能。demo3:-----小方块上下移动-----demo在线地址:https://googlechrome.github.io/devtools-samples/jank/源码截图:未优化【每个方块需要强制布局计算位置]:点击优化按钮进行优化[只读一次,存入pos变量]:再次优化[添加transform:translateZ(0),提高层级]:以上是一个小case动画渐进优化:具体操作可以查看原文:https://developer.chrome.com/docs/devtools/evaluate-performance/3.2如何优化动画性能根据上面对渲染机制的讨论,我们可以看到影响动画渲染的因素是帧流水线。从我们经历的每个阶段,我们可以总结出一些优化动画性能的方法:提高每一帧的性能,避免频繁重排,避免大规模重绘,优化JS性能,稳定fps,避免掉帧和跳帧如果是不可避免的非连续动画时加入高耗能操作,可在动画开始或结束时启动操作,开启GUP加速。第四部分是常用的动画库。以上实现方式可以支持一些动画开发,比如点击交互。、轮播,以及纯动画展示,如摇钱树、烟花等。如果需要强交互,或者需要重力世界,原生JS的实现难度比较大。您可以使用一些动画库进行开发。这些动画是基于canvas和webGL实现的。Pixi.js添加场景,添加玩家,添加自己的动作,添加交互phaser.js物理系统,重力系统可以模仿下落状态其他:create.js,three.js3d渲染,layaAir,Egret3d游戏引擎等,可以根据不同的使用场景,选择不同的框架来使用。动画实现手段总结浏览器渲染简单流程动画分析开发性能使用参考性能参考致谢非常感谢您对本文的指正和建议,也感谢鹿一、双旭等小伙伴的帮助和帮助合作企业产品技术支持。