带你重新认识浏览器的渲染机制——重绘重排

栏目: CSS · 发布时间: 5年前

内容简介:性能优化中,减少重绘重排应该是一种很好的优化方式,我们具体看一下什么情况下会造成重绘重排,为什么减少重绘重排可以做到优化,怎么样减少重绘重排。我们先看看当浏览器拿到服务端返回的资源时,是如何渲染的。首先浏览器会进行文件解析,主要解析三个东西:

性能优化中,减少重绘重排应该是一种很好的优化方式,我们具体看一下什么情况下会造成重绘重排,为什么减少重绘重排可以做到优化,怎么样减少重绘重排。

浏览器渲染过程

我们先看看当浏览器拿到服务端返回的资源时,是如何渲染的。

首先浏览器会进行文件解析,主要解析三个东西:

  1. 解析 html/xhtml/svg,形成 dom 树。
  2. 解析 css,产生 CSS Rule Tree。
  3. 解析 js,js 会通过 api(包括 DOM API 和 CSSOM API) 来操作 Dom Tree 和 CSS Rule Tree。

解析完成之后

  1. 通过 CSS Rule Tree 和 Dom Tree 生成 rendering Tree。其中不包括 display:none 的元素。
  2. 计算 DOM 节点的位置,对元素进行分层及布局,也叫 reflow 和 layout 过程。

布局完成之后,就要进行绘制了,将各层发给 GPU,GPU 将各层合成,显示在屏幕上,即 composite。

什么情况下会造成重绘重排

当我们开始绘制的时候,如果使用 js 操作了 dom 元素,或者改变了 css 属性,就可能会造成重绘(repaint)和重排(reflow)。

repaint:屏幕的一部分进行了重画,比如某个 css 中改变背景色,元素尺寸没有变。 reflow:任何一个元素的尺寸发生了变化,需要重新验证并计算 render tree,就会造成重排。

在 PC 时代,我们用 jquery 进行获取元素,改变元素的尺寸,及时发生重排,我们也很难感知到,但是当移动时代到来之后,如果频繁发生重排,那手机就会受不了了。

尤其是在执行下面操作时,成本会很高:

  1. js 添加或者删除元素的时候
  2. js 改变元素的位置发生改变时
  3. 页面初始化
  4. 容器尺寸发生变化。比如在标准盒模型下添加 padding,border 就会造成重排,所以在书写样式的时候,很多会将盒模型设计成怪异盒模型(box-sizing: border-box)
  5. js 获取元素的尺寸单位。
    • offsetTop, offsetLeft, offsetWidth, offsetHeight
    • scrollTop/Left/Width/Height
    • clientTop/Left/Width/Height
    • IE 中的 getComputedStyle(), 或 currentStyle

如果发生上述的行为基本都会造成重绘和重排。

当发生重排时,一定会发生重绘,但是发生重绘不一定会发生重排。

浏览器中每个元素节点都有 reflow 方法,当一个元素发生 reflow 时,他的子节点都会发生 reflow。

举几个例子来说明一下造成重绘重排的情况:

var bodyStyle = document.body.style; // cache

bodyStyle.padding = '20px'; // reflow, repaint
bodyStyle.border = '10px solid red'; //  再一次的 reflow 和 repaint

bodyStyle.color = 'blue'; // repaint
bodyStyle.backgroundColor = '#fad'; // repaint

bodyStyle.fontSize = '2em'; // reflow, repaint

// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('children!'));
复制代码

为什么减少重绘重排可以优化性能

前面说了浏览器的渲染机制,多一次重绘就需要浏览器重新进行一次绘制,及时 GPU 处理会比较快,但是也是吃不消的,更别说重排了,重排一个 dom,会重新生成 render Tree,然后重新绘制。

如何减少重绘重排

其实浏览器很聪明,不可能每次修改样式就 reflow 或者 repaint 一次,一般来说,浏览器会积累一批操作,然后做一次 reflow。

但是也有些例外情况,比如 resize 窗口,改变窗口字体,浏览器会立即进行 reflow。

虽然浏览器会这么做,但是我们也应该减少重绘重排的次数,在开发阶段就为浏览器进行特殊的关爱,毕竟是每天陪伴我们的小伙伴。

下面总结了一些针对 reflow 和 repaint 的最佳实践:

  1. 不要一条一条的修改 DOM 样式,尽量提前设置好 class,后续增加 class,进行批量修改。
  2. 把 DOM 离线后修改。
    • 使用 documentFragment 对象在内存里操作 DOM。
    • 使用 requestAnimationFrame 可以进行优化,在下一帧进行操作。
    • 把修改频繁的元素先 display: none,修改完之后显示,修改个 100 次也无妨。
    • clone 一个 dom 节点在内存里,修改之后;与在线的节点相替换。
  3. 不要把 DOM 元素的属性值放到一个循环中当成循环的变量。
  4. 尽可能的修改低层级的节点,避免修改高层级的节点,造成大面积的 reflow。
  5. 千万不要使用 table 布局,修改一小块地方,会造成整个 table 重新布局。
  6. 动画尽量使用 css 动画,css 动画中尽量只使用 transform 和 opacity,这不会发生重排和重绘

composite

当每次布局完成之后,就会发生 composite 过程,浏览器都把重绘后的图像发给 GPU 去合成并显示。

在上面最佳实践中最后提到了动画,动画其实是比较耗费性能的,因为动画的每一帧都会发给 GPU 去合成,重绘重排会发生在动画的每一帧。

我们在写动画的时候,可以通过 js 写,也可以通过 css 写。两种方式在写动画时,过程也是不一样的。

  1. js 写的动画,过程:js 计算 -> 重排(若布局改变) -> 重绘 -> 合成
  2. css 动画,过程:重排(若布局改变)-> 重绘 -> 合成

所以不难看出,耗费性能最少并能并最流畅的动画是只触发合成。

为了仅发生 composite,我们做动画的 css property 必须满足以下三个条件:

  1. 不影响文档流。
  2. 不依赖文档流。
  3. 不会造成重绘。

满足以上以上条件的 css property 只有 transform 和 opacity。

这样的话,由于没有重排和重绘,只有合成,那么浏览器在动画执行之前就知道动画如何开始和结束。

并且有两个优势:

  1. 动画将会非常流畅
  2. 动画不在绑定到 CPU,即使 js 执行大量的工作;动画依然流畅

事实上影响动画流畅性的因素不止重排重绘,还有 CPU 内存。

css 动画有一个重要的特性,它是完全工作在 GPU 上。因为你声明了一个动画如何开始和如何结束,浏览器会在动画开始前准备好所有需要的指令;并把它们发送给 GPU。

而如果使用 js 动画,浏览器必须计算每一帧的状态;为了保证平滑的动画,我们必须在浏览器主线程计算新状态;把它们发送给 GPU 至少 60 次每秒。

除了计算和发送数据比 css 动画要慢,主线程的负载也会影响动画; 当主线程的计算任务过多时,会造成动画的延迟、卡顿。

所以最佳实践中最后一条就提到了,在写动画时,尽量写 css 动画,并且尽量用 transform 和 opacity。

辅助工具

谷歌浏览器检测重绘工具:右上角...,more tools,rendering。

带你重新认识浏览器的渲染机制——重绘重排

勾选了 paint flashing 时,在刷新页面之后,就会发现有有绿色的背景,有绿色的背景就代表着重排。

还可以勾选 FPS meter,可以查看渲染页面时候 GPU 的使用率。

方便发现自己在开发过程中,哪些操作造成了重绘重排,尽量减少修改次数,优化性能。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Introduction to Programming in Java

Introduction to Programming in Java

Robert Sedgewick、Kevin Wayne / Addison-Wesley / 2007-7-27 / USD 89.00

By emphasizing the application of computer programming not only in success stories in the software industry but also in familiar scenarios in physical and biological science, engineering, and appli......一起来看看 《Introduction to Programming in Java》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试