css帧动画点击执行一次_深入浅出动画帧后,我再也不怕动画了

本文详细探讨了浏览器动画帧的优化,包括JavaScript的requestAnimationFrame、分块执行、style与layout的优化、减少paint区域、利用transform和opacity以及composite层管理。通过了解和应用这些技巧,可以提高动画流畅性和前端性能。
摘要由CSDN通过智能技术生成

作者:三羊

来源:https://snayan.github.io/post/2019/in_depth_animation_frame/

在前端性能优化策略中,耳熟能详的手段有,雅虎 35 条军规,使用 cache,减少请求数量,使用cookie-free domain,critical asset,使用 CDN,Lazy load,PreLoad 等,这些手段其实主要都是围绕怎么样更快的拿到所需关键资源。当我们把这一步做到很好,没有可优化空间了,其实还可以从另外一个方向去做优化,那就是浏览器渲染方面。浏览器渲染优化是一个很大的主题,今天,我们只谈它一个小角度,动画帧。从动画帧,我们可以怎么样来做一些优化工作呢?本文篇幅较长,图较多,耐心看完,一定会有很多收获的。

基础概念

先还是来熟悉基础概念。帧,可以理解为浏览器每一次绘制的快照。1s 内绘制的次数,叫做帧率,也就是我们常说的 fps(frame per second)。帧率越大,浏览器在 1s 内绘制的次数就越多,动画就越流畅。人们视觉系统对帧率的最低要求一般是 24fps,当帧率低于 24 时,就会感觉到明显的卡顿了。不同的移动设备,有不同的帧率,一般默认是 60fps。

09732f061b221bfca398f7076df56eca.png
frame

我们要追求的理想帧率是 60fps,那么一帧绘制的时间最多是 1 / 60 = 16.7ms,一旦超过这个数,就达不到 60fps 了。为了使得一帧花费的时间控制在 16.7ms 内,我们必须先搞清楚浏览器在一帧会做些什么事情呢?

帧任务

html,js,css 是浏览器处理最为常见的三种资源,也是我们前端工程师每天都会打交道的文件。可是我们真正知道浏览器是怎么绘制的吗?稍微思考一下,然后会说,html 解析为 dom tree,css 解析为 cssom tree,然后 dom tree 加上 cssom tree 就合并为 render tree,最后浏览器根据 render tree 绘制到屏幕上。这是我们最为熟知的步骤,但是它只是描述了一个整体大致的过程,并没有具体到一帧的绘制过程。下面看看一帧具体绘制的过程图。

c61a7799e9c0094f32fcd64d42b64d6b.png
step

上图就是浏览器在绘制一帧时,会经过的处理步骤。

  • JavaScript,我们会通过 js 来改动一些视觉效果,比如基于 js 的动画,或者响应用户事件等。

  • Style,如果通过 js 改变了某一个 dom 的样式,就会重新计算受影响的元素的样式。

  • Layout,如果样式改变中涉及了布局属性,例如 top,left,width 等几何位置,还会重新计算它的布局位置,以及受影响的其他元素的布局。当然,如果不涉及布局样式,也不会执行这一步。

  • Paint,计算出 Style 和 Layout 后,就可以把元素绘制到它所属的 paint layer 上。

  • Composite,最后会将多个 composite layer 输出到屏幕上显示出来。

要控制一帧的执行时间在 16.7ms 内,就只需要把上述 5 个步骤处理时间总和控制在 16.7ms 内。接下来,我们一个步骤一个步骤来看,有哪些优化建议。

JavaScript

requestAnimationFrame

JavaScript 是前端工程师的利器,有了它,我们可以实现非常复杂的系统,或者非常流畅的游戏等。JavaScript 通常会处理用户输入或者点击等事件,然后做一系列的视觉效果的改变。当涉及 dom 元素改变时,总是把操作放在requestAnimationFrame

requestAnimationFrame会有什么神奇之处呢?

  • 它总是会确保 fn 的执行在浏览器一帧的开头

  • 浏览器会自动调节帧率,间接调节了 fn 的执行频率

在不支持 raf 的浏览器中,通常使用setTimeout(fn, 16.7)来实现。但是setTimeout有一些不好的地方,

  • 它并不是保证 fn 每隔 16.7ms 就执行一次,它只能每 16.7ms 将 fn 加入到MacroTask Queue中,具体什么时候执行,要根据当前执行队列决定

  • 它不能保证每次执行时机都是一帧的开头,可能某一次执行触发是在帧的中间或者结尾,导致延长当前帧在 16.7ms 内无法执行完成,就会出现丢失当前帧

  • 不同设备帧率不一样,并不是固定的 60fps,给低帧率(比如 30fps)的设备上执行setTimeout(fn, 16.7)将会导致执行很多无意义的 fn

我们先使用setTimeout来实现,每 16.7ms 就更

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值