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

css渲染优化

时间:2023-04-02 20:14:50 HTML

在日常开发中,通过css属性做一些动效和动画,会发现页面出现卡顿现象;在低端Android设备上尤为明显,因此需要了解浏览器渲染和优化方法浏览器渲染过程构建了DOM树:浏览器将HTML解析成树状的DOM树。一般来说,这个过程发生在页面第一次加载时,或者页面JavaScript修改节点结构时。构建渲染树:浏览器将CSS解析成树状结构的CSSOM树,然后与DOM树合并形成渲染树。布局:浏览器根据渲染树中反映的节点、每个节点的CSS定义及其从属关系,计算出每个节点在屏幕上的位置。网页中元素的布局是相对的。页面元素位置和大小的变化往往会导致其他节点联动,需要重新计算布局。此时的布局过程一般称为回流/重排(Reflow)。Paint:遍历渲染树,调用渲染器的paint()方法将节点内容绘制到屏幕上,本质上是一个像素填充过程。当由于回流或一些不影响布局的CSS修改而导致屏幕部分重绘时,也会发生此过程。这个时候就叫Repaint。实际上,绘制过程是在多个层上完成的,我们称之为渲染层(RenderLayer)。渲染层合成(Composite):将多个渲染后的渲染层按照适当的重叠顺序进行合并,然后生成位图,最终通过显卡显示在屏幕上。以上就是浏览器渲染的基本步骤,简单说一下:DOM树+CSS树==Render树==>Layout树==>PaintLayer=>CompositePaintLayer=>Composite只要页面上的元素发生变化,上面的步骤会重复渲染,在一帧(16.77ms)内完成;通过设置css样式和做动画,无法在一帧内完成渲染,或者来不及渲染也会卡顿;部分渲染卡顿,这与渲染层合成(Composite)关系有关。Composite什么是渲染层合成?DOM树中的每个节点对应一个渲染对象(RenderObject)。当它们的渲染对象在同一个坐标空间(z轴空间)时,会形成一个RenderLayers,也就是渲染层。渲染层将确保页面元素以正确的顺序堆叠。这时候就会出现图层合成(composite)来正确处理透明元素和重叠元素的显示。此步骤称为“堆叠上下文”。这种模型类似于Photoshop的图层模型,在Photoshop中,每一个设计元素都是一个独立的图层,多个图层按适当的顺序叠加在z轴空间上,最终形成一张完整的设计图。这个过程对于有重叠元素的页面尤为重要,因为一旦图层合并顺序错误,元素就会显示异常。渲染对象(RenderObject)一个DOM节点对应一个渲染对象,渲染对象仍然保持着DOM树的树状结构。渲染层(RenderLayer)这是浏览器渲染时构建的第一层模型。在同一个坐标空间(z轴空间)的渲染对象会合并到同一个渲染层。因此,根据堆叠上下文,不同坐标空间渲染的对象会形成多个渲染层来体现它们的级联关系。因此,一个满足形成堆叠上下文条件的RenderObject,必然会为其创建一个新的渲染层。当然还有其他一些特殊情况,就是为一些特殊的RenderObject创建一个新的渲染层,比如overflow!=visibleelements。根据创建RenderLayer的不同原因,可以分为常见的三类:NormalPaintLayer根元素(HTML)具有明确的定位属性(relative、fixed、sticky、absolute)透明(opacity小于1)具有CSS过滤器(filter)具有CSSmask属性具有CSSmix-blend-mode属性(非正常)具有CSStransform属性(非无)具有隐藏的背面可见性属性具有CSS反射属性具有CSScolumn-count属性(非自动)或具有CSScolumn-width属性(不是auto)目前有opacity,transform,filter,backdrop-filter的动画,OverflowClipPaintLayeroverflow不可见NoPaintLayer,不需要paint的PaintLayer,比如没有视觉属性(background,color,shadow等)的空div.)。满足上述条件的RenderObjects将拥有一个独立的渲染层,而其他RenderObjects将与其第一个具有渲染层的父元素共享一个。GraphicsLayer渲染层与其拥有GraphicsLayer的第一个父层共享一个。每个GraphicsLayer都有一个GraphicsContext,负责输出图层的位图。位图存储在共享内存中,并作为纹理上传到GPU。最后,GPU合成多个位图,然后绘制到屏幕上,此时,我们的页面就显示在屏幕上了。合成层(CompositingLayer)满足某些特殊条件的渲染层会被浏览器自动提升为合成层。合成层有一个单独的GraphicsLayer。渲染层必须满足哪些特殊条件才能提升为合成层?这里列举一些常见的情况:3D变换:translate3d、translateZ等元素,如video、canvas、iframe等Element.animate()实现的不透明动画变换СSS动画position:fixed实现的不透明动画变换有will-change属性对opacity、transform、fliter、backdropfilterapplyanimationortransitioncommonpractical**transforms:translate3d,translateZ**形成复合层,对原布局示例无影响其他合成情况隐式合成另外,当浏览处理器的Composite阶段,也有一个隐含的合成,在某些特定场景下会默认将一些渲染层提升为合成层。其实就是元素div相互重叠,如上图所示:position-1生成复合层,后面的元素会相互重叠,这样堆叠上下文才能正确显示;后面的元素直接和隐含地合成;图层压缩如上图所示,目前没有遇到合成爆炸。通过上图的研究,很容易产生一些不在预期范围内的合成层。当这些不符合预期的合成层数达到一定程度时,就会成为层数爆炸。需要检查是否有重叠,是否可以通过z-index调整堆叠顺序来优化优势。合成层的位图会由GPU合成,比CPU处理快很多;当需要重绘时,只需要重绘本身,不影响其他图层;transform和opacity元素提升为复合层后不会触发repaint,如果不是复合层,仍然会触发repaint。(只有css动画可用,js在控制的时候还是会重排重绘)使用transform或者opacity实现动画效果,更新元素几何属性(重排发生)。浏览器会触发重新布局,经过解析阶段会产生一系列子元素,这个过程称为重排。毋庸置疑,重排需要更新完整的渲染管线,所以成本也是最大的。页面的第一次渲染;浏览器窗口的大小发生变化;元素的内容发生变化;元素的大小或位置发生变化;元素的字体大小变化;激活CSS伪类;查询某些属性或调用某些方法;offsetTop,offsetLeft,offsetWidth,offsetHeightscrollTop,scrollLeft,scrollWidth,scrollHeightclientTop,clientLeft,clientWidth,clientHeightwidth,heightgetComputedStyle()getBoundingClientRect()添加或删除可见的DOM元素。更新元素的绘图属性(发生重绘)。如果修改了元素的背景色,则不会执行布局阶段,因为不会引起几何位置的变换,所以直接进入绘制阶段,然后执行后续的一系列子阶段,这个过程称为重绘。与重排操作相比,重绘省去了布局和分层阶段,因此执行效率会比重排操作高。Rearrangementofvisibility:visible<=>hiddencolorchangesothergeometricchanges...在直接合成阶段,我们使用CSStransform实现动画效果,可以避免重排和重绘阶段,直接在非Composite动画操作是在主线程上执行。这种效率是最高的,因为是在非主线程上合成的,不占用主线程的资源,也避免了布局和绘制两个子阶段,所以相对于重绘和重排,合成可以大大提高绘图效率。缺点绘制的图层必须传输到GPU。当这些层的数量和大小达到一定程度时,传输可能会很慢,在一些中低端设备上可能会造成闪烁;隐式合成容易出现过多的合成层,每个合成层都会占用额外的内存,而内存在移动设备上是宝贵的资源,过多的内存使用可能会导致浏览器崩溃,因此值得进行性能优化其他优化的css使用transform而不是topUsevisibility改为display:none,因为前者只会引起重绘,后者会引起回流(改变布局避免使用表格布局,一个小的改变可能会导致整个表格重新布局。尽量改变在DOM树类的末尾,回流是不可避免的,但可以减少它的影响。尽可能多地更改DOM树末尾的类可以限制回流的范围并使其影响尽可能少的节点。避免设置多层内联样式,CSS选择器从右到左匹配搜索,避免节点层级过多。给position属性为absolute或fixed的元素应用动画效果,避免影响其他元素的布局。这只是重绘,不是回流。同时可以选择requestAnimationFrame来控制动画速度。有关详细信息,请参阅讨论requestAnimationFrame。避免使用CSS表达式,这可能会导致重排。将频繁重绘或回流的节点设置为一个层。图层可以防止节点的渲染行为影响到其他节点,比如will-change、video、iframe等标签,浏览器会自动将节点变成图层。js:为了避免频繁操作样式,最好一次性重写样式属性,或者将样式列表定义为一个类,一次性更改类属性。为避免频繁操作DOM,创建一个documentFragment,在其上应用所有DOM操作,最后将其添加到文档中。避免频繁读取会导致回流/重绘的属性。如果你真的需要多次使用它,使用一个变量来缓存它。对动画复杂的元素使用绝对定位,使其远离文档流,否则会造成父元素和后续元素的频繁回流。综上所述,在做动画的时候尽量使用csstransforms属性。它跳过Layout和Paint阶段,直接进入渲染,所以会提升一些性能。同时查看物业的空间位置是否提升了构图层次;还要注意元素是否重叠,防止复合层爆炸;这样至少可以保证在css方面性能上尽量没有问题。其余请看其他优化方法示例代码overlap

参考:transform和leftchangingtheposition的性能差异Chrome浏览器GPUAcceleratedCompositing图层合成和页面渲染优化浏览器渲染页面流程和页面优化无线性能优化:CompositebrowserrenderingprocessRenderingprocessSticktoCompositor-OnlyPropertiesandManageLayerCount