高性能网页动画实践

发布于 2022-07-23 22:46:37 字数 2984 浏览 146 评论 0

渲染过程

渲染流程

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

  1. Recalculate Style: 计算(应用到元素上的)样式。
  2. Layout: 为(渲染树上)每个元素生成几何形状(大小和位置)。
  3. Paint:为每个元素填充像素到layer。
  4. 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内把一帧准备好。

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

  1. 开始渲染的时机
  2. 渲染一帧的时间

渲染时机

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; // 读属性,强制layout
el2.style.height = (h2 + 4)+ 'px'; // 等待layout

var h3 = el3.clientHeight; // 读属性,强制layout
el3.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 区域

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

梦纸

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

1CH1MKgiKxn9p

文章 0 评论 0

ゞ记忆︶ㄣ

文章 0 评论 0

JackDx

文章 0 评论 0

信远

文章 0 评论 0

yaoduoduo1995

文章 0 评论 0

霞映澄塘

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文