高性能网页动画

前端精髓

共 2167字,需浏览 5分钟

 ·

2021-03-31 20:13

渲染流程

在开发者工具的timeline里,我们可以看到一个典型的渲染过程基本如下:

Recalculate Style: 计算(应用到元素上的)样式。

Layout:为(渲染树上)每个元素生成几何形状(大小和位置)。

Paint:为每个元素填充像素到layer。

Composite Layers : 把所有layer绘制,输出到屏幕。

渲染小结

渲染主要三阶段:Layout计算范围,Paint计算展现,Composite合成Bitmap。

修改不同CSS属性会触发不同阶段。比如width,height,margin,left/top等等会触发layout;box-shadow,border-radius,background,outline等等触发paint;transform,opacity触发composite layer。

触发的阶段越前,渲染的代价越高。

硬件加速(GPU加速)

术语:texture。可看做放在GPU上的位图

GPU擅长对texture进行偏移,缩放,旋转,更改透明度

Layer模型

浏览器根据CSS属性为元素生成Layers。

将Layers作为texture上传到GPU。

改变Layer的transform,opacity属性时,渲染会跳过Layout和paint阶段,直接通知GPU对Layer做变换。

Layer触发条件

3d或perspective transform属性

使用animation,transition改变opacity,transform的元素

video

canvas

flash

css filters

满足上述某个条件,浏览器就会单独创建一个layer。

硬件加速节省了哪些时间

CPU进行Layout,Paint的时间

CPU向GPU传输位图的时间

流畅动画

什么叫流畅?60fps,即要在16.7ms内把一帧准备好。

想要流畅需考虑两个问题:

开始渲染的时机

渲染一帧的时间

渲染时机

setTimeout不够精确

依靠浏览器内置时钟更新频率。IE8及以前更新间隔为15.6,setTimeout 16.7意味着需要两个15.6才能触发,超出14.5Ms。

main thread队列

setTimeout不够精确会导致丢帧,因为屏幕刷新频率60HZ是不变的。比如设置setTimeout 16,每隔一段时间后,就会有丢帧。

requestAnimationFrame

定义绘制每一帧前的工作。requestAnimationFrame(callback)

自动调节频率。callback工作太多无法在一帧内完成,会自动降为30fps,降频比丢帧好。

渲染一帧的时间

从Layout来减小渲染时间

触发Layout

更改class,导致width,height,margin等size,position相关属性改变

读取size,position相关属性。一般浏览器会批量更新,但你读取时为保证你读取的属性正确,强制进行一次Layout。

读取以下属性会引起Layout:

clientHeight/Left/Top/Width, focus(),getBoundingClientRect(),getClientRects(),innerText,offsetHeight/Left/Top/Width/Parent,outerText(),scrollByLines(),scrollByPages(),scrollHeight/Left/Top/Width,scrollIntoView()...

尽量不触发Layout

用transform代替top/left

不要频繁Layout

var h1 = el1.clientHeight;el1.style.height = (h1 + 4)+ 'px'; // 等待layout
var h2 = el2.clientHeight; // 读属性,强制layoutel2.style.height = (h2 + 4)+ 'px'; // 等待layout
var h3 = el3.clientHeight; // 读属性,强制layoutel3.style.height = (h3 + 4)+ 'px'; // 等待layout

分离读写操作,比如用requestAnimationFrame把写操作推到下一帧。

Layout小结

不但改变CSS可能导致Layout,读取位置大小相关的属性也会导致Layout

分离读写,减少Layout

面对解偶代码,使用requestAnimationFrame推迟的方法分离读写。

从Paint来减小渲染时间

触发Paint

修改box-shadow,border-radius,color等展示相关属性时,会触发Paint

Paint代价

box-shadow等Paint代价昂贵。

减少不必要的Paint

gif图即使被其它Layer盖住,也可能导致Paint,不必要时应该将gif图的display设置none

减小Paint区域


浏览 25
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报