高性能Web动画和渲染原理系列(5)合成层的生成条件和陷阱
示例代码托管在: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节点包含使用了硬件加速的Canvas2D或WebGL技术 - 使用了
CSS透明效果或CSS变形动画 - 使用了硬件加速的
CSS Filters技术(有的文献中表示filters属性并没有提升为合成层的效果,推测只有一部分filters滤镜效果需要使用硬件加速,并非所有) - 使用了剪裁
Clip或者反射Reflection,并且它的后代中包含一个合成层 - 拥有一个Z坐标比自己小的兄弟节点,且该节点是一个合成层。
上面的规则里我们最熟悉的可能就是transform:translateZ(0)或者在关键帧动画的定义中改变transform和opacity属性。当然,随着技术的演进,上面的规则并不一定全面,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硬件加速也有坑中的示例更加详细,子元素引发父元素提升,父元素又引发兄弟元素提升。
三. 硬件加速的权衡
所有的技术方案都是有代价的,这是亘古不变的道理,合成层的好处很明显,GPU比CPU的处理速度快很多,触发repaint重绘时,只需要重绘独立的层,然后重新合成即可,不需要重绘整个画面。但它也存在一些弊端:首先是数据传输的问题,CPU和GPU的关系就好比客户端和服务端一样,它们的协作是需要传输数据的,当层的数量达到一定量级后,传输的速度就会影响到整体的处理效率,进而导致在一些低中端设备上出现闪烁等现象;另外,每个合成层都具会占据额外的内存,这个数量通常比开发者以为的要大的多,尤其是在移动端这种硬件资源受限制的场景中,过量的内存使用分分钟就会让应用崩溃。
四. 动画实现的一些建议
使用
transform实现动画这可能是我们编写动画时听到最多的建议了。例如使用
left和top来实现位置动画时,绝对定位的元素会形成RenderLayer,但是却不符合提升为CompositingLayer的条件,所以动画元素就会和Document处在同一个合成层里,持续进行的动画就会导致Document这一层(通常是正常文档流这一层,包含了大量的流式布局的元素)不断重绘,从而影响渲染效率,如果能够让动画的节点放到单独的合成层里,就可以避免这种大规模重绘,并借助GPU加速合成的能力加速整个渲染流程。排查被动提升的情形
被动提升主要是指“兄弟元素相对层级低于自己但却是一个合成层”的情形以及“发生堆叠遮挡的几个元素中层级较低的元素被提升为合成层”的状况。一般的解决方案是主动提升动画元素的
z-index值或者调整文档结构中节点的先后顺序,当然所有的结果都还需要通过测试来确认。考虑合成层的空间占用
合成层的后端存储是渲染后的像素点数据,它的体积可能会非常大,在使用大屏图片时需要尽可能将其压缩至视觉可接受的范围而不能一味追求高清,对于纯色的元素,可以使用较小的尺寸并借助
transform:scale来放大至需要的尺寸。实测为王
任何方案都只是一种思路,必须通过在真实环境测试验证才能确认其有效性。
高性能Web动画和渲染原理系列(5)合成层的生成条件和陷阱的更多相关文章
- 高性能Web动画和渲染原理系列(2)——渲染管线和CPU渲染
目录 一. 高性能动画 二. 像素渲染管线 基本渲染流程 回流和重绘 三. 旧软件渲染 渲染对象(RenderObject) 渲染层(RenderLayer) 四. 从canvas体会分层优势 不分层 ...
- 高性能Web动画和渲染原理系列(3)——transform和opacity为什么高性能
示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文目录 华为云社区地址:[你要的前端打怪升级指南] [T ...
- 高性能Web动画和渲染原理系列(1)——CSS动画和JS动画
[摘要] 介绍CSS动画和JS动画的基本特点,以及轻量级动画库velocity.js的基本用法. 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园 ...
- 高性能Web动画和渲染原理系列(4)“Compositor-Pipeline演讲PPT”学习摘要
目录 摘要 1.合成流水线 2. 预定义UI层 3. paint是什么意思 4. 分层的优势和劣势 5. 视图属性及其处理方式 6. Quads 7. Compositor Frame 8. 关于光栅 ...
- Web高性能动画及渲染原理(1)CSS动画和JS动画
目录 一. CSS动画 和 JS动画 1.1 CSS动画 1.2 JS动画 1.3 小结 二. 使用Velocity.js实现动画 示例代码托管在:http://www.github.com/dash ...
- web前端知识大纲:系列三 html篇
web前端庞大而复杂的知识体系的组成:html.css和 javascript 三.HTML 1.BOM BOM 是 Browser Object Model的缩写,即浏览器对象模型,当一个浏览器页面 ...
- 【Web动画】CSS3 3D 行星运转 && 浏览器渲染原理
承接上一篇:[CSS3进阶]酷炫的3D旋转透视 . 最近入坑 Web 动画,所以把自己的学习过程记录一下分享给大家. CSS3 3D 行星运转 demo 页面请戳:Demo.(建议使用Chrome打开 ...
- nginx高性能WEB服务器系列之六--nginx负载均衡配置+健康检查
nginx系列友情链接:nginx高性能WEB服务器系列之一简介及安装https://www.cnblogs.com/maxtgood/p/9597596.htmlnginx高性能WEB服务器系列之二 ...
- 《Nginx高性能Web服务器》系列分享专栏
<Nginx高性能Web服务器>系列分享专栏 [作者:Poechant] Nginx是目前最流行的基于BSD-like协议.轻量级.高性能的HTTP服务器.反向代理服务器和电子邮件(SMT ...
随机推荐
- SpringMVC快速入门记录(二)
一.数组参数绑定和List参数绑定 1.数组参数绑定 提交多个相同name的参数,保持name的名字和Controller方法参数的数组名称相同即可. 2.List参数绑定 List中存放对象,并将定 ...
- Java编程思想——第17章 容器深入研究 读书笔记(一)
这一章将学习散列机制是如何工作的,以及在使用散列容器时怎么样编写hashCode()和equals()方法. 一.容器分类 先上两张图 来概况完整的容器分类 再细说都为什么会有那些特性. 二.填充容器 ...
- 代码审计-凡诺CMS 2.1文件包含漏洞
0x01代码审计 后台账号密码: admin admin 安装好了是这样的 漏洞文件:/channel.php if (ism()) { include($dir.$t_mpath.$c_mcmode ...
- iview和element中日期选择器快捷选项的定制控件
公司的两个vue项目中都用到了iview和element这个框架,最近的两个需求都有关于日期选择的定制控件,就是要求日期选择的快捷选项左边栏有包含今日.昨日.本周.上周.最近一周.本月.上月.上季 ...
- Mysql面试题及千万级数据查询优化
今天在说Mysql查询优化之前,我先说一个常见的面试题,并带着问题深入探讨研究.这样会让大家有更深入的理解. 一,Mysql数据库中一个表里有一千多万条数据,怎么快速的查出第900万条后的100条数据 ...
- Js极客之路 - 优化操作(性能优化)
1.因为每次For循环都会计算一次arr.length,所以有必要存储数组长度以减少计算.针对这篇文章(http://www.crimx.com/2015/04/21/should-array-len ...
- “Triplet network”三元组网络阅读笔记
记录<DEEP METRIC LEARNING USING TRIPLET NETWORK>阅读笔记 文章总体内容: 作者在前人提出的多个特征提取方法的基础上提出Triplet netwo ...
- Intellij idea 自动生成serialVersionUID
1 什么是UID 网络间的数据传输最终都是要转化为二进制流的方式进行传输,为了方便转换以及进行验证,我们应该把对角序列化,当实现Seriabizable接口时,UID就是一个必须的属性,可以方便进行版 ...
- The usage of Markdown---列表
目录 1. 序言 2. 有序列表 3. 多级有序列表 3. 无序列表 4. 多级无序列表 5. 列表中的转义字符 6. 无效化 7. 任务列表 更新时间:2019.09.14 1. 序言 其实我昨 ...
- 数据类型(三) + 流程控制(一) day05
目录 昨日回顾 (三) 花式赋值 链式赋值 交叉赋值 (四) 列表list (五) 字典dict (六) 布尔值 (七) 解压缩 (八) python与用户交互的方式 (九) 三种格式化输出的方式 f ...