首页IT科技前端 入门 动画 canvas(前端动画实现以及原理浅析)

前端 入门 动画 canvas(前端动画实现以及原理浅析)

时间2025-05-02 01:08:54分类IT科技浏览3839
导读:背景 如今的前端是一个涉猎领域很广的职业。作为一名前端,我们不仅要开发管理系统、数据中台、还要应对年报开发、节日活动等场景。不仅要会增删改查,编写表单,还要具备开发动画、H5 游戏等能力。能做出很 Cool 的动画效果,也是一种前端特有的成就感。所以,我们从动画的实现方法入手,了解浏览器的渲染,以及如何提升动画的性...

背景

如今的前端是一个涉猎领域很广的职业            。作为一名前端            ,我们不仅要开发管理系统            、数据中台                    、还要应对年报开发       、节日活动等场景                    。不仅要会增删改查                    ,编写表单       ,还要具备开发动画            、H5 游戏等能力       。能做出很 Cool 的动画效果            ,也是一种前端特有的成就感            。所以                   ,我们从动画的实现方法入手       ,了解浏览器的渲染      ,以及如何提升动画的性能                   。

我们先来看 2 个 H5 案例 :

【一镜到底】

<->手机扫码体验

【年报】

【其他 H5 优秀案例】

https://www.h5anli.com

第一部分 常见的动画实现手段

1.1 gif 实现

定义:

GIF 文件的数据是一种基于 LZW 算法的连续色调的无损压缩格式                   ,gif 格式的特点是一个 gif 文件可以存多幅彩色图像             ,当数据逐幅读出并展示都在屏幕上      ,就可以构成一个简单的动画       。

最高支持 256 种颜色      。由于这种特性                   ,GIF 比较适用于色彩较少的图片             ,比如页面卡通 icon                   、标志等等                   。

使用:

![file](https://cdn.yuucn.cn/wp-content/uploads/2022/08/1660320389-6446d860dbbfe54.png)

优点:

1.制作的成本很低;

2.兼容性好;

3.方便开发使用             。

缺点:

1.画质上:色彩支持少,图像毛边严重;

2.交互上:不能控制动画的播放暂停                   ,没有灵活性;

3.大小上:由于是无损压缩                    ,每帧被完整的保存下来,导致文件很大      。

1.2 css3 补帧动画

1.2.1 transition 过渡动画

使用:

.box { border: 1px solid black; width: 100px; height: 100px; background-color: #0000ff; transition: width 2s, height 2s, background-color 2s, transform 2s; } .box:hover { background-color: #ffcccc; width: 200px; height: 200px; transform: rotate(180deg); }

场景:

常与 :hover, :active 等伪类使用,实现相应等动画效果                   。

1.2.2 animation 关键帧动画

使用:

.bounce1 { left: -40px; animation: bouncy1 1.5s infinite; } .bounce2 { left: 0; animation: bouncy2 1.5s infinite; } .bounce3 { left: 40px; animation: bouncy3 1.5s infinite; } @keyframes bouncy1 { 0% { transform: translate(0px, 0px) rotate(0deg); } 50% { transform: translate(0px, 0px) rotate(180deg); } 100% { transform: translate(40px, 0px) rotate(-180deg); } }

场景: 比如:loading 展示            ,代码如上             。

优点:

1       、无需每一帧都被记录                    ,通过关键帧设置       ,方便开发;

2.实现简单            ,通常 UI 可以直接给到 css 文件                   ,前端只需要导入即可【移动端注意屏幕适配】。

缺点:

1.css 没法动画交互       ,无法得知当前动画执行阶段;

2.transition: 需要触发      ,无法自动播放;

3.animation 兼容性需要加前缀                   ,导致代码量成倍增长;

4.对于复杂动画的实现             ,导入的 css 文件过大      ,影响页面的渲染树生成                   ,从而阻塞渲染                   。比如实现一个摇钱树的效果             ,css 文件达到百 kb,就要采取一些必要的压缩手段                   ,缩减文件大小                    。

1.3 js 逐帧动画

JS 动画的原理是通过 setTimeout 或 requestAnimationFrame 方法绘制动画帧                    ,从而动态地改变

网页中图形的显示属性(如 DOM 样式,canvas 位图数据            ,SVG 对象属性等)                    ,进而达到动画的目的。

demo1:

------- js 实现一个正方形从左到右的移动动画 ----- setTimeout 实现 const element2 = document.getElementById(raf2); const btn2 = document.getElementById(btn2); let i = 0; let timerId; function move () { element2.style.marginLeft = i + px timerId = setTimeout(move, 0) i++; if (i > 200) { clearTimeout(timerId) } } btn2.addEventListener(click,function () { move() }) requestAnimationFrame 实现 const element = document.getElementById(raf); const btn1 = document.getElementById(btn1); let r = 0; let rafId; function step () { 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 的执行很快                    。这是为什么呢?请接着往后看~

第二部分 浏览器如何渲染与动画的渲染

2.1 浏览器的帧原理

问题 2:当 url 输入到一个页面展示出来经过了哪些过程?

这里我们忽略 http 请求静态文件之前的步骤                   ,着重看浏览器渲染帧是怎么做的       ,从而找到浏览器是如何渲染动画的       。

借助 chrome-performance【执行 raf.html】 同样可以看出上图不同阶段在 performance 里面的标注            。⚠️注意:不是每帧都总是会经过管道每个部分的处理                   。实际上      ,不管是使用 JavaScript      、CSS 还是网络动画                   ,在实现视觉变化时             ,管道帧对指定帧的运行通常有三种方式:

【以下截图是以时间线为主轴      ,进行绘制】

-当修改一些会触发 layout 的属性                   ,则会导致后面的同样被更新       。

当修改只改变 paint 的属性             , 则不会重新 layout      。 如果改一些不涉及布局也不涉及重绘的数据,则可以直接进行合成渲染                   。

像 CSS 属性具体可以查询这个网站 ,去查阅哪些属性会引起怎样的帧管道:https://csstriggers.com/

例如:transform 变换                   ,它是一个不会触发布局与绘制的变化的                    ,所以使用它的时候,直接进入第三种状态            ,在合成之后                    ,直接进入 Composite 阶段       ,是一个很好的优化手段             。

问题 3: 控制台上显示出 requestAnimationFrame(rAF)的执行            ,那么这个 rAF 执行与浏览器帧有什么关系呢?我们接着往下看      。

2.2 requestAnimationFrame 执行

我们还是运行 demo1 的代码:

可以看到 rAF 执行在 layout 与 paint 之前                   ,在每帧只执行了一次 rAF       ,调用回调函数执行动画                   。

从 rAF 的执行时机      ,可以看出 setTimeout 的执行时机与 rAF 的不同             。

我们通过对不同方式实现方块移动动画的 performance 抓取                   ,可以看到:

setTimeout 单位帧截图: rAF 单位帧截图:

对比两者可以看出             ,在 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 的情况            ,也可以逐帧去分析影响 scripting\rendering\painting 时间的因素                   ,从而有针对性的提高动画的性能                   。

demo3:

----- 小方块的上下运动 -----

demo 的在线地址:https://googlechrome.github.io/devtools-samples/jank/

源码截图:

未优化【每个方块都需要强制 layout 去计算 position】:

点击 Optimize 按钮优化后【只读一次       ,并存在 pos 变量中】:

再次优化【添加 transform:translateZ(0)      ,提高层级】:

以上就是一个动画逐步优化的小案例:具体操作可以查看原文:

https://developer.chrome.com/docs/devtools/evaluate-performance/

3.2 如何优化动画性能

根据上文的渲染机制的讨论                   ,我们可以看出             ,影响动画渲染的因素就是帧管道所经历的各个阶段      ,从中我们可以总结一些用来优化动画性能的手段:

提升每一帧的性能 避免频繁的重排 避免大面积的重绘 优化 JS 的性能 fps 稳定                   ,避免掉帧             ,跳帧的情况 不在连续动画中,添加高耗能的操作 如果无法避免                   ,看可以在动画的开头或者结尾进行操作 开启 GUP 加速

第四部分 常用的动画库

综上的实现方式可以支持部分的动画开发                    ,比如点击交互,轮播器                   、以及纯动画的展示            ,比如摇钱树             、烟花等       。

如果需要强交互                    ,或者是需要一个重力世界的时候       ,原生 JS 的实现相对于困难      。可以利用一些动画库            ,来进行开发                   ,这些动画基于 canvas 与 webGL 实现的                   。

Pixi.js 添加场景 添加玩家 添加自身动作 添加交互

phaser.js

物理系统、重力系统

可以模仿下落状态

其他:

create.js                   、three.js 3d 渲染                    、layaAir、Egret 3d 游戏引擎等       ,可以根据不同的场景需要      ,选择不同的框架使用             。

总结

动画的实现手段 浏览器渲染的简单流程 开发动画分析性能参考 performance 的使用

鸣谢

非常感谢木杪            、千寻对本文的校正与建议                   ,同时感谢琉易                    、霜序等伙伴在业务产品技术上帮助与支持      。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
嫉妒是一个人对另一个人发自内心的认可(GCC strict aliasing – 嫉妒就是承认自己不如别人) 外部链接的重要性(外部链接优化步骤)