• 浏览器的重绘与重排


    一、基本概念 

     浏览器从下载文件至本地到显示页面是个复杂的过程,这里包含了重绘和重排。在页面的生命周期中,一些效果的交互都有可能发生重排(Layout)和重绘(Painting),这些都会使我们付出高额的性能代价。 

      通常来说,渲染引擎会解析HTML文档来构建DOM树,与此同时,渲染引擎也会用CSS解析器解析CSS文档构建CSSOM树。接下来,DOM树和CSSOM树关联起来构成渲染树(RenderTree),这一过程称为Attachment。然后浏览器按照渲染树进行布局(Layout),最后一步通过绘制显示出整个页面。如下图所示:

      一旦触发重排,我们对DOM的修改引发了DOM几何元素的变化,渲染树需要重新计算, 而重绘只会改变visibilityoutline、背景色等属性导致样式的变化,使浏览器需要根据新的属性进行绘制。

      更比而言,重排会产生比重绘更大的开销。所以,我们在实际生产中要严格注意减少重排的触发。

    二、触发重排的操作

      触发重排的操作主要是几何因素。

        1.页面第一次渲染 在页面发生首次渲染的时候,所有组件都要进行首次布局,这是开销最大的一次重排。

      2.浏览器窗口尺寸改变

      3.元素位置和尺寸发生改变的时候

      4.新增和删除可见元素

      5.内容发生改变(文字数量或图片大小等等)

      6.元素字体大小变化。

      7.激活CSS伪类(例如::hover)。

      8.设置style属性

      9.查询某些属性或调用某些方法。比如说:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight

      除此之外,当我们调用getComputedStyle方法,或者IE里的currentStyle时,也会触发重排,原理是一样的,都为求一个“即时性”和“准确性”。

    三、触发重绘的操作

      当visibilityoutline、背景色等属性的改变时,会触发重绘。

      我们应当注意的是:重绘不一定导致重排,但重排一定会导致重绘。

    四、避免或减少重排的方法

      1.分离读写操作

    div.style.top = "10px";
    div.style.bottom = "10px";
    div.style.right = "10px";
    div.style.left = "10px";
    console.log(div.offsetWidth);
    console.log(div.offseHeight);
    console.log(div.offsetRight);
    console.log(div.offsetLeft);

      原来的操作会导致四次重排和四次重绘,变换顺序之后只会触发一次重排 在第一个console的时候,浏览器把之前上面四个写操作的渲染队列都给清空了。因为渲染队列本来就是空的,所以剩下的console并没有触发重排,仅仅拿值而已。

      2.样式集中改变

      通过classcssText进行集中改变样式 未进行优化的代码是这样的:

    //bad
    var left = 10;
    var top = 10;
    el.style.left = left + "px";
    el.style.top = top + "px";

       虽然现在大部分现代浏览器都会有Flush队列进行渲染队列优化,但是有些老版本的浏览器比如IE6这样的坑货效率依然低下: 这时我们就可以通过上面所说的利用classcssText属性集中改变样式。

    //good
    el.className += " className";
    //or
    el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

      3. 缓存布局信息

    // bad 强制刷新 触发两次重排
    div.style.left = div.offsetLeft + 1 + 'px';
    div.style.top = div.offsetTop + 1 + 'px';
    
    // good 缓存布局信息 相当于读写分离
    var curLeft = div.offsetLeft;
    var curTop = div.offsetTop;
    div.style.left = curLeft + 1 + 'px';
    div.style.top = curTop + 1 + 'px';

      4. 将DOM离线

      一旦我们给元素设置display:none时,元素不会存在于渲染树中,相当于将其从页面“拿掉”,我们之后的操作将不会触发重排和重绘,这叫做DOM的离线化。

    dom.display = 'none'
    // 修改dom样式
    dom.display = 'block'

      5. 将position属性设置为absolutefixed

      position属性为absolutefixed的元素,重排开销比较小,不用考虑它对其他元素的影响。

      6. 优化动画

      动画效果还应牺牲一些平滑,来换取速度,这中间的度自己衡量:

      比如实现一个动画,以1个像素为单位移动这样最平滑,但是Layout就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。

      7.启用GPU加速

      GPU 硬件加速是指应用 GPU 的图形性能对浏览器中的一些图形操作交给 GPU 来完成,因为 GPU 是专门为处理图形而设计,所以它在速度和能耗上更有效率。

       GPU 加速通常包括以下几个部分:Canvas2D,布局合成, CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。

  • 相关阅读:
    补间动画
    nginx+php的配置
    腾讯QQ首次在PC端采用气泡式聊天界面(from:36kr)
    mysql errno:13
    PHP高级面试题
    Nginx下fastcgi_split_path_info导致CodeIgniter配置问题
    ngx_http_fastcgi_module 的那些事
    PowerShell 定时刷新查看文件内容
    解决 VMWARE MAC 10.12无法全屏的问题
    libcurl 函数curl_easy_perform在release下崩溃的问题
  • 原文地址:https://www.cnblogs.com/gg-qq/p/10750780.html
Copyright © 2020-2023  润新知