当前位置: 首页 > Web前端 > HTML

浏览器渲染魔法合成层

时间:2023-03-28 00:25:52 HTML

本文作者:Backflow一、前言浏览器与前端开发的关系不言而喻,了解浏览器的渲染原理可以帮助我们提升页面性能,解决一些渲染问题.问题。最近在开发手机H5页面的时候,遇到了一个奇怪的问题。最新版IOS手机列表页标签切换时,左上角倒计时闪烁。让我们看看一些效果。一般的代码结构是通过插件检查的。DOM结构正常,风格与其他手机一致。那么问题是什么?我觉得大概率是最新版IOS浏览器渲染的问题。说起这种渲染问题,我第一时间想到的是用GPU渲染升级成复合层,于是加了一小行代码will-change:transform到倒计时DOM,顺利解决了问题.倒计时模块渲染不再受其他内容影响。为什么添加此代码以使用GPU渲染并将其提升到合成层?什么是合成层?让我们来看看。2.浏览器渲染过程在讨论合成层之前,我们先简单了解一下浏览器渲染。浏览器常见的渲染引擎有Webkit/Gecko等,它们的主要渲染流程基本相同。这里主要讨论WebKit的简化渲染过程。浏览器下载并解析HTML。处理CSS以构建CSSOM树并生成DOM树。DOM和CSSOM合并为一棵渲染树。通过RenderTree,浏览器可以知道每个节点的CSS定义和它们的从属关系,从而计算出每个节点在屏幕上的位置,生成一个足够大的画布来容纳所有元素。层根据浏览器提供的各层信息合成并显示在屏幕上。本文主角的构图层出现在流程的最后一步。这些合成层中的一些特殊层被认为是合成层(CompositingLayers)。让我们来看看它的由来。3.关于合成层3.1什么是合成层(CompositingLayer)首先,合成就是把页面的每一部分分成多个图层,分别光栅化(浏览器根据文档的结构,每一个的样式元素,页面的几何图形和绘图顺序转换为屏幕上的像素)并在合成器线程中合成为单个页面。如何观察页面的层结构,需要在Chrome开发工具中打开自定义菜单,然后在Moretools中选择Layers选项。这样就可以观察到页面的层次结构。详情可以看demo。一般来说,具有某些特定属性的渲染层会被浏览器自动提升为合成层。复合层有一个单独的层(GraphicsLayer),其他层之间没有影响。而其他不属于合成层的渲染层与拥有该层的第一个父层共享一个,即普通文档流中的内容。让我们看一下提升到合成层的一些常见属性。设置transform:translateZ(0),注意必须是translateZ,因为它是用GPU计算透视畸变的。透视是3D设计中的一个重要属性。有兴趣的同学可以阅读本资料一探究竟。如果您使用translateX或translateY,该元素将在正常文档流演示中绘制。backface-visibility:hidden指定当元素的背面面向查看者时演示是否可见。will-change属性告诉浏览器元素会发生什么变化,以便浏览器提前做好相应的优化准备。demo当这个属性的值为opacity,transform,top,left,bottom,right。video、canvas、iframe等元素。3.2关于隐式合成隐式合成是指在某些场景下,默认会提升到合成层的情况。具体的我们可以看一下前面层结构的demo。只要我们交换B和C的z-index,就会发现B被隐式提升为复合层。只是z-index引起的吗?如果我们调整一些B的位置,保证B和C、D没有交集,那么你会发现这次B并没有被隐式提升到复合层。因此,引用CSSGPU动画中隐式合成的描述:这称为隐式合成:一个或多个按堆叠顺序应出现在合成元素之上的非合成元素被提升为合成层——即绘制成单独的图像,这些元素是然后发送到GPU。应按堆叠顺序出现在复合元素上方的一个或多个非复合元素被提升为复合层。3.3层压缩和层爆炸根据我们刚才提到的例子,如果在堆叠顺序的最下面有一个复合元素,会不会导致堆叠顺序上的大量元素被提升为复合层?其实在大多数情况下,我们在开发过程中并没有注意图层合成的问题,所以才有可能出现我们刚刚提到的情况。当这些不符合预期的合成图层达到一定程度时,就会发生图层爆炸,导致你的页面占用大量的内存资源,带来一些意想不到的情况。例如,当WKWebView(WKWebView是一个多进程组件,意味着内存会从APP内存中分离出来成为一个单独的进程)的内存超过系统分配给它的内存时,浏览器就会崩溃,会出现白屏,但APP不会崩溃。这是我们不想看到的情况。对于这个问题,浏览器也有相应的解决方案。如果多个渲染层与一个合成层重叠,这些渲染层将被压缩为一层,以防止由于重叠导致的层爆炸。我们看下面的代码B、C、D应该都提升为复合层,但是由于层压缩,它们会在一层中渲染。近年来,浏览器在这方面的优化越来越好。比如我们来看一下CSS3硬件加速和打坑文章中提供的一个有趣的demo。该页面包含一个h1标题,该标题已将动画应用于转换,因此它被提升到合成层。由于动画变换的特殊性(动态重叠是不确定的),不重叠也可以发生隐式合成,这就导致页面中z-index高于它的节点对应的所有渲染层都提升为合成层,这页面最终产生了数千个复合层。然后当我在电脑上测试这个例子的时候,突然发现上千个合成层消失了,页面极其流畅。为什么?我的浏览器版本是Chrome96,找了谷歌的history包,终于发现这个问题在Chrome94Releases中得到了优化。GoogleChrome93Release版本GoogleChrome96Release版本查看了Chrome94的更新日志,其中提到了一个修复:1238944MediumCVE-2021-37966:InappropriateimplementationinCompositing。MohitRaj(shadow2639)于2021-08-11报道修复合成中因相应issue没有权限访问导致的不正确现象,有兴趣的同学可以看看。层压缩的存在并不意味着我们可以肆无忌惮的改进合成层,尤其是在一些对渲染速度要求高的页面,或者加载速度较慢的页面,我们更应该注意页面的层级结构,简化其复杂度绘图,以提高页面性能。4.合成层的优缺点渲染层提示的好处:启用硬件加速,合成层的位图会由GPU合成,比CPU处理速度更快。重绘复合图层时,不会影响其他图层。对于变换和不透明效果,不会触发布局和绘制。当然,在合成层也存在一些问题:如果我们将所有的渲染工作都交给GPU,在现有的优化下,会导致渲染内存占用率大幅上升,但负面影响也会出现。此外,隐式综合往往会产生大量意想不到的综合层。过多的内存占用会使页面卡住,性能优化适得其反。5.总结5.1使用transform和opacity实现动画在我们日常的开发中,经常会实现一些动画。有时候我们可能会选择改变top/left来实现,那么这个节点的渲染就会发生在正常的文档流中。使用transform和opacity实现动画可以让节点放在一个独立的复合层进行渲染绘制,动画不会影响其他层,而且GPU渲染可以比CPU更快,让你的动画更流畅,一起来看看吧在他们的分歧。通过left实现动画:通过transform实现动画:可以看到通过transform实现动画,页面的fps可以稳定在60左右,而通过left有波动,fps大概稳定在30左右,将影响您的用户体验指标。注意:检查帧率的UI唤醒方法如果您不确定使用此属性是否有意义,在您使用任何CSS属性进行动画之前,您可以在csstriggers上查看此属性对渲染管道的影响。5.2谨慎使用will-change。我认为除非你的元素的某个属性真的存在并且会立即改变,比如transform,你可以使用will-change:transform来通知浏览器,根据你打算改变的元素,浏览器可能会预-排列,元素变化和渲染更快。但是这些属性可能会给你带来一些副作用,我们来看一个demo。任何具有position:fixed或position:absolute的子元素将相对于具有will-change:transform集的元素定位。所以当你使用它的时候,你需要确保这个意外的包含块不会影响到你。另外,浏览器对will-change属性的进一步优化往往会消耗更多的资源。如果应用到太多的属性上,显然是一种浪费,而且即使使用得非常过度,也可能导致相应的页面速度变慢或者直接崩溃。5.3减小合成层的绘图区合成层绘图区的大小对其内存占用影响很大。举个例子:可以看到A的大小是B的5倍,我们通过transform:scale(5)将B放大到200×200像素,但是它们的内存占用相差了25倍之多。您可以节省大量内存,而用户看不到任何差异。当然这个例子只适用于这种纯色场景,我们需要看到的是绘图区域对内存占用的影响。相关信息CSSGPU动画:正确执行坚持仅用于合成器的属性并管理层数使用Chrome中的新图层面板消除内容重绘无线性能优化:复合层以及如何强制使用Chrome中的GPU加速合成层以及如何强制使用内部查看现代网页浏览器(三)本文由网易云音乐前端团队发布。未经授权禁止任何形式的转载。我们常年招前端、iOS、Android。如果你准备换工作,又恰好喜欢云音乐,那就加入我们吧grp.music-fe(at)corp.netease.com!