zoukankan      html  css  js  c++  java
  • 回流和重绘

    在搞清楚回流和重绘的概念之前,我们要清楚浏览器的渲染过程。

    渲染主流程

      渲染引擎首先通过网络获得所请求文档的内容,通常以8K分块的方式完成。下面是渲染引擎在取得内容之后的基本流程:

      解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树

      这里先解释一下几个概念,方便大家理解:

      (1)DOM Tree:浏览器将HTML解析成树形的数据结构。

          CSS Rule Tree:浏览器将CSS解析成树形的数据结构。

      (2)Render Tree: DOM和CSSOM合并后生成Render Tree。

      (3)Layout: 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置。

      (4)painting: 按照算出来的规则,通过显卡,把内容画到屏幕上。

    更详细一点来说:

         1. 浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。

      2. 将CSS解析成 CSS Rule Tree 。

      3. 根据DOM树和CSSOM来构造 Rendering Tree。注意:Rendering Tree 渲染树并不等同于 DOM 树,因为一些像Header或display:none的东西就没必要放在渲染树中了

      4. 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步操作称之为layout,顾名思义就是计算出每个节点在屏幕中的位置。

      5. 再下一步就是绘制,即遍历render树,并使用UI后端层绘制每个节点。

      注意:上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容

      reflow(回流):当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,内行称这个回退的过程叫 reflow。reflow 会从 <html> 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。

      repaint(重绘):改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。

    注意:(1)display:none 的节点不会被加入Render Tree,而visibility: hidden 则会,所以,如果某个节点最开始是不显示的,设为display:none是更优的。

         (2)display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发现位置变化。

       (3)有些情况下,比如修改了元素的样式,浏览器并不会立刻reflow 或 repaint 一次,而是会把这样的操作积攒一批,然后做一次 reflow,这又叫异步 reflow 或增量异步 reflow。但是在有些情况下,比如resize 窗口,改变了页面默认的字体等。对于这些操作,浏览器会马上进行 reflow。

    通过上诉我们知道:回流必定引发重绘,重绘不一定引发回流回流的代价比重绘高。

    1)搞清楚了回流和重绘的概念,我们很容易知道哪些属性的修改会引起回流:

    • DOM的添加和删除;
    • 页面的加载;
    • 元素尺寸改变——边距、填充、边框、宽度和高度;
    • 元素位置的改变;
    • 内容变化,比如用户在input框中输入文字;
    • 浏览器窗口尺寸改变——resize事件发生时;

    2)常见引起重绘的属性:

     

    3)如何减少回流、重绘:

    • 使用 transform 替代 top
    • 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
    • 不要把节点的属性值放在一个循环里当成循环里的变量。
    • 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
    • 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame
    • CSS 选择符从右往左匹配查找,避免节点层级过多
    • 将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。比如对于 video 标签来说,浏览器会自动将该节点变为图层。

       

      浏览器的回流优化机制:浏览器会维护1个队列,把所有会引起重排、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的重排、重绘变成一次重排重绘。

    transform为什么不会触发重排的操作
    1.合成(composite)
    2.那么使用CSS3的transform来实现动画是否可以避免重排问题?或者说浏览器针对这一部分做了其他优化?

    经过一番查找,答案如下:

    CSS的最终表现分为以下四步:Recalculate Style -> Layout -> Paint Setup and Paint -> Composite Layers

    按照中文的意思大致是 查找并计算样式 -> 排布 -> 绘制 -> 组合层

    这上面的几个步骤有点类似于上文说到的重排必定导致重绘,而查询属性会强制发生重排。所以上文提到的重排重绘内容可以结合这里进行理解。

    由于transform是位于Composite Layers层,而width、left、margin等则是位于Layout层,在Layout层发生的改变必定导致Paint Setup and Paint -> Composite Layers,所以相对而言使用transform实现的动画效果肯定比left这些更加流畅

    PS:层叠加就生成大量的合成层,但是不要创建太多的渲染层。因为每创建一个新的渲染层,就意味着新的内存分配和更复杂的层的管理,

    在内存资源有限的设备上,合成层带来的性能改善,可能远远赶不上过多合成层开销给页面性能带来的负面影响。这一点浏览器也考虑到了,因此就有了层压缩(Layer Squashing)的处理.如果多个渲染层同一个合成层重叠时,这些渲染层会被压缩到一个 GraphicsLayer (图层)中,以防止由于重叠原因导致可能出现的“层爆炸”。

  • 相关阅读:
    如何在某些情况下禁止提交Select下拉框中的默认值或者第一个值(默认选中的就是第一个值啦……)
    渗透测试
    如何制作chrome浏览器插件之一
    linux中的vi命令
    链栈
    二进制转16进制JAVA代码
    抽象数据类型的表示与实现
    变量的引用类型和非引用类型的区别
    说明exit()函数作用的程序
    计算1-1/x+1/x*x
  • 原文地址:https://www.cnblogs.com/haoqiyouyu/p/14042512.html
Copyright © 2011-2022 走看看