示例代码托管在:http://www.github.com/dashnowords/blogs

博客园地址:《大史住在大前端》原创博文目录

华为云社区地址:【你要的前端打怪升级指南】

一. 硬件加速相关的几个概念

之前介绍到了RenderLayer渲染层的概念,在涉及到硬件加速的话题时,出现了很多新的概念,参考《Webkit技术内幕》一书的介绍总结如下:

Webkit决定将哪些RenderLayer对象组合在一起,形成一个有后端存储的新层,这一新层不久后会用于合成,这里称之为合成层CompositingLayer)。每一个合成层都会对应一个或多个后端存储,由RenderLayerBacking类进行统一管理,后端存储空间使用GraphicsLayer来表示,也就是说RenderLayerBacking管理着一个或多个与对应的合成层有关的GraphicsLayer

笔者旁白:对于渲染过程来说,只需要理解这里形成了新的CompositingLayer合成层就可以了,其他的层概念基本都是用于实现对CompositingLayer功能支持的,概念数量太多对于理解宏观流程是一大障碍。

二. 合成层的生成条件

显式提升

合成层的处理是依赖于硬件加速的,但是GPU的存储空间有限最好不要滥用,过多的合成层有可能还会造成相反的效果,所以浏览器只会将满足下列任意条件的RenderLayer提升为CompositingLayer

  • 具有CSS3D属性或CSS透视效果
  • 包含的RenderObject节点表示的是使用硬件加速的视频解码技术的HTML5video元素
  • 包含的RenderObject节点包含使用了硬件加速的Canvas2DWebGL技术
  • 使用了CSS透明效果或CSS变形动画
  • 使用了硬件加速的CSS Filters技术(有的文献中表示filters属性并没有提升为合成层的效果,推测只有一部分filters滤镜效果需要使用硬件加速,并非所有)
  • 使用了剪裁Clip或者反射Reflection,并且它的后代中包含一个合成层
  • 拥有一个Z坐标比自己小的兄弟节点,且该节点是一个合成层。

上面的规则里我们最熟悉的可能就是transform:translateZ(0)或者在关键帧动画的定义中改变transformopacity属性。当然,随着技术的演进,上面的规则并不一定全面Chromium官网提供的开发者演讲PPT中也对提升的理由进行了相关的描述:

你可以在Chrome调试面板的【Layers】功能中对分层相关的结果进行检视,查看哪些层进行了提升以及被提升的具体原因,避免出现与自己意图相悖的层提升:

隐式提升

RenderLayer满足特殊条件时被提升为CompositingLayer对开发者而言是比较可控的。但除此之外,在浏览器的合成阶段,还存在隐式合成的状况,一些特定的场景中出现的合成层并不是开发者主观期望的。

隐式合成主要发生在元素出现重叠时,层级较低的元素如果被提升为合成层后,最终合成的结果就可能出现在原来比自己层级更高的元素之上,从而出现错误的堆叠关系,为了纠正这种关系,只能让原本层级高(但是并不用提升为合成层的元素)发生提升也成为合成层。例如下面的代码:

<div style="position:absolute;height:200px;width:200px;background-color: #DA5961;"></div>
<div style="position:absolute;left:30px;top:50px;height:200px;width:200px;background-color: #3498db;"></div>
<div style="position:absolute;left:60px;top:100px;height:200px;width:200px;background-color: #1abc9c;"></div>

三个div盒子堆叠在一起,可以看到它们都绘制在同一个层上(这里的层并不与RenderLayer对应,毕竟它只是一个中间态的树结构):

此时如果为最底下的红色矩形添加transform:translateZ(0)属性将其提升为合成层后,为了保证正确的堆叠关系,蓝色和绿色的矩形就会被提升为合成层,代码如下:

<div style="transform:translateZ(0);position:absolute;height:200px;width:200px;background-color: #DA5961;"></div>
<div style="position:absolute;left:30px;top:50px;height:200px;width:200px;background-color: #3498db;"></div>
<div style="position:absolute;left:60px;top:100px;height:200px;width:200px;background-color: #1abc9c;"></div>

蓝色和绿色的矩形并没有形成独立的合成层,而是被压缩在同一个合成层中:

从上图中的细节信息中可以看到,提升的原因是layerFotSquashingContent,也就是为了保证堆叠顺序的正确,用一个单独的合成层来将受到影响的元素收集在一起,既保证堆叠顺序,也避免在期望之外生成过多的合成层。如果调整绿色矩形的位置,就可以看到,当视觉上不存在覆盖时,它就不需要提升了:

BUT!!!还没完,最坑的部分来了,如果此时给蓝色的div加上一点动画,你会发现绿色div又被提升到了独立的合成层上,尽管他们之间并没有重叠区,但还是被提升了:

从图中的合成原因可以看到:它可能和一个相邻的合成层元素发生交叠,所以被提升了。没错,就是“可能”。Fouber这篇CSS硬件加速也有坑中的示例更加详细,子元素引发父元素提升,父元素又引发兄弟元素提升。

三. 硬件加速的权衡

所有的技术方案都是有代价的,这是亘古不变的道理,合成层的好处很明显,GPUCPU的处理速度快很多,触发repaint重绘时,只需要重绘独立的层,然后重新合成即可,不需要重绘整个画面。但它也存在一些弊端:首先是数据传输的问题,CPUGPU的关系就好比客户端和服务端一样,它们的协作是需要传输数据的,当层的数量达到一定量级后,传输的速度就会影响到整体的处理效率,进而导致在一些低中端设备上出现闪烁等现象;另外,每个合成层都具会占据额外的内存,这个数量通常比开发者以为的要大的多,尤其是在移动端这种硬件资源受限制的场景中,过量的内存使用分分钟就会让应用崩溃。

四. 动画实现的一些建议

  1. 使用transform实现动画

    这可能是我们编写动画时听到最多的建议了。例如使用lefttop来实现位置动画时,绝对定位的元素会形成RenderLayer,但是却不符合提升为CompositingLayer的条件,所以动画元素就会和Document处在同一个合成层里,持续进行的动画就会导致Document这一层(通常是正常文档流这一层,包含了大量的流式布局的元素)不断重绘,从而影响渲染效率,如果能够让动画的节点放到单独的合成层里,就可以避免这种大规模重绘,并借助GPU加速合成的能力加速整个渲染流程。

  2. 排查被动提升的情形

    被动提升主要是指“兄弟元素相对层级低于自己但却是一个合成层”的情形以及“发生堆叠遮挡的几个元素中层级较低的元素被提升为合成层”的状况。一般的解决方案是主动提升动画元素的z-index值或者调整文档结构中节点的先后顺序,当然所有的结果都还需要通过测试来确认。

  3. 考虑合成层的空间占用

    合成层的后端存储是渲染后的像素点数据,它的体积可能会非常大,在使用大屏图片时需要尽可能将其压缩至视觉可接受的范围而不能一味追求高清,对于纯色的元素,可以使用较小的尺寸并借助transform:scale来放大至需要的尺寸。

  4. 实测为王

    任何方案都只是一种思路,必须通过在真实环境测试验证才能确认其有效性。

高性能Web动画和渲染原理系列(5)合成层的生成条件和陷阱的更多相关文章

  1. 高性能Web动画和渲染原理系列(2)——渲染管线和CPU渲染

    目录 一. 高性能动画 二. 像素渲染管线 基本渲染流程 回流和重绘 三. 旧软件渲染 渲染对象(RenderObject) 渲染层(RenderLayer) 四. 从canvas体会分层优势 不分层 ...

  2. 高性能Web动画和渲染原理系列(3)——transform和opacity为什么高性能

    示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文目录 华为云社区地址:[你要的前端打怪升级指南] [T ...

  3. 高性能Web动画和渲染原理系列(1)——CSS动画和JS动画

    [摘要] 介绍CSS动画和JS动画的基本特点,以及轻量级动画库velocity.js的基本用法. 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园 ...

  4. 高性能Web动画和渲染原理系列(4)“Compositor-Pipeline演讲PPT”学习摘要

    目录 摘要 1.合成流水线 2. 预定义UI层 3. paint是什么意思 4. 分层的优势和劣势 5. 视图属性及其处理方式 6. Quads 7. Compositor Frame 8. 关于光栅 ...

  5. Web高性能动画及渲染原理(1)CSS动画和JS动画

    目录 一. CSS动画 和 JS动画 1.1 CSS动画 1.2 JS动画 1.3 小结 二. 使用Velocity.js实现动画 示例代码托管在:http://www.github.com/dash ...

  6. web前端知识大纲:系列三 html篇

    web前端庞大而复杂的知识体系的组成:html.css和 javascript 三.HTML 1.BOM BOM 是 Browser Object Model的缩写,即浏览器对象模型,当一个浏览器页面 ...

  7. 【Web动画】CSS3 3D 行星运转 && 浏览器渲染原理

    承接上一篇:[CSS3进阶]酷炫的3D旋转透视 . 最近入坑 Web 动画,所以把自己的学习过程记录一下分享给大家. CSS3 3D 行星运转 demo 页面请戳:Demo.(建议使用Chrome打开 ...

  8. nginx高性能WEB服务器系列之六--nginx负载均衡配置+健康检查

    nginx系列友情链接:nginx高性能WEB服务器系列之一简介及安装https://www.cnblogs.com/maxtgood/p/9597596.htmlnginx高性能WEB服务器系列之二 ...

  9. 《Nginx高性能Web服务器》系列分享专栏

    <Nginx高性能Web服务器>系列分享专栏 [作者:Poechant] Nginx是目前最流行的基于BSD-like协议.轻量级.高性能的HTTP服务器.反向代理服务器和电子邮件(SMT ...

随机推荐

  1. 宝塔面板6.x版本前台存储XSS+后台CSRF组合拳Getshell

    对于宝塔漏洞复现和练习 0×00  什么是宝塔面板 宝塔面板是一款使用方便,功能强大且终身免费的服务器管理软件,支持Linux 与Windows 系统.一键配置:LAMP / LNMP ,网站,数据库 ...

  2. Python之selenium+pytesseract 实现识别验证码自动化登录脚本

    今天写自己的爆破靶场WP时候,遇到有验证码的网站除了使用pkav的工具我们同样可以通过py强大的第三方库来实现识别验证码+后台登录爆破,这里做个笔记~~~ 0x01关于selenium seleniu ...

  3. vi/vim编辑器使用方法详解

    vi编辑器是所有Unix及Linux系统下标准的编辑器,他就相当于windows系统中的记事本一样,它的强大不逊色于任何最新的文本编辑器.他是我们使用Linux系统不能缺少的工具.由于对Unix及li ...

  4. 为程序员节日献礼--2019中国.NET开发者峰会主题内容发布

    2019年10月24日,组委会正式发布了China .NET Conf 2019中国 .NET 开发者峰会的主题内容. 2014年微软组织并成立.NET基金会,微软在成为主要的开源参与者的道路上又前进 ...

  5. Dubbo+Zookeeper(一)Zookeeper初识

    前面花了一段时间去学习SpringCloud的相关知识,主要是理解微服务的概念并使用SpringCloud的一系列组件实现微服务落地.学习这些组件本身是简单的,跟着操作一遍基本就会了,这也得益于Spr ...

  6. 四jmeter脚本开发

    4.1工作区介绍 4.2http协议录制 a.使用badboy进行录制(目前公司测试系统使用badboy界面不友好,暂时不用,之后再补充) b.jmeter代理服务器进行录制 (1)浏览器代理配置(以 ...

  7. 1.在ubuntu中软件安装在哪里?

    ubuntu下安装软件有四种方式: 1.通过deb格式的离线软件包安装 sudo dpkg -i xxx.deb # 安装包,安装程序   -i: install sudo dpkg -r packa ...

  8. Java代码优化建议

    总结日常Java开发常见优化策略,持续更新. 尽可能使用局部变量 调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中,速度较快,其他变量,如静态变量.实例变量等,都在堆中创建,速度较慢.另外, ...

  9. PAT-1022 Digital Library (30 分) 字符串处理

    A Digital Library contains millions of books, stored according to their titles, authors, key words o ...

  10. 用最复杂的方式学会数组(Python实现动态数组)

    Python序列类型 在本博客中,我们将学习探讨Python的各种"序列"类,内置的三大常用数据结构--列表类(list).元组类(tuple)和字符串类(str). 不知道你发现 ...