浏览器渲染原理(性能优化之如何减小重排和重绘)

继续上篇《浏览器地址栏里输入URL后的全过程javascript

前言

为何要了解浏览器的渲染原理?了解浏览器的渲染原理有什么好处?咱们作前端开发为何非要了解浏览器的原理?直接把网页作出来,什么需求,直接一把梭,撸完收工很差吗。css

可是常常会有人会问,什么是重排重绘html

重排也叫回流Reflow),重绘Repaint),会影响到浏览器的性能,给用户的感受就是网页访问慢,或者网页会卡顿,不流畅,从而使网页访问量降低。前端

因此,想要尽量的避免重排重绘,就须要了解浏览器的渲染原理java

浏览器工做流程

上图咱们能够看出,浏览器会解析三个模块:web

  • HTML,SVG,XHTML,解析生成DOM树。
  • CSS解析生成CSS规则树。
  • JavaScript用来操做DOM APICSSOM API,生成DOM TreeCSSOM API

解析完成后,浏览器会经过已经解析好的DOM TreeCSS规则树来构造 Rendering Treeshell

  • Rendering Tree 渲染树并不等同于DOM树,由于一些像Headerdisplay:none的东西就不必放在渲染树中了。浏览器

  • CSSRule Tree主要是为了完成匹配并把CSS Rule附加上Rendering性能优化

  • Tree上的每一个Element。也就是DOM结点,即Frame。而后,计算每一个Frame(也就是每一个Element)的位置,这又叫layoutreflow过程。markdown

  • 最后经过调用操做系统Native GUIAPI绘制。

不一样内核的浏览器渲染

上图是 webkit内核的渲染流程,和整体渲染流程差很少,要构建 HTMLDOM Tree,和 CSS规则树,而后合并生成 Render Tree,最后渲染。

这个是 MozillaGecko渲染引擎。
整体看来渲染流程差很少,只不过在生成渲染树或者 Frame树时,二者叫法不一致, webkit称之为 LayoutGecko叫作 Reflow

渲染顺序

  • 当浏览器拿到一个网页后,首先浏览器会先解析HTML,若是遇到了外链的css,会一下载css,一边解析HTML
  • css下载完成后,会继续解析css,生成css Rules tree,不会影响到HTML的解析。
  • 当遇到<script>标签时,一旦发现有对javascript的引用,就会当即下载脚本,同时阻断文档的解析,等脚本执行完成后,再开始文档的解析。

  • DOM树和CSS规则树已经生成完毕后,构造 Rendering Tree
  • 调用系统渲染页面。

什么状况会形成重排和重绘。

重排意味着元件的几何尺寸变了,咱们须要从新验证并计算Render Tree。是Render Tree的一部分或所有发生了变化。这就是Reflow,或是Layout

重排由于要从新计算Render Tree,并且每个DOM Tree都有一个reflow方法,一旦某个节点发生重排,就有可能致使子元素和父元素甚至是同级其余元素的reflow,浪费大量的时间从新验证Render Tree

所以,重排的成本要比重绘高不少。

如下操做会致使重排重绘

  • 删除,增长,或者修改DOM元素节点。
  • 移动DOM的位置,开启动画的时候。
  • 修改CSS样式,改变元素的大小,位置时,或者将使用display:none时,会形成重排;修改CSS颜色或者visibility:hidden等等,会形成重绘
  • 修改网页的默认字体时。
  • Resize窗口的时候(移动端没有这个问题),或是滚动的时候。
  • 内容的改变,(用户在输入框中写入内容也会)。
  • 激活伪类,如:hover。
  • 计算offsetWidthoffsetHeight

若是当前网页含有一些动画,或者固定不动元素的网页时,因为滚动也会发生重排,一旦发生滚动,当前浏览器所承受的压力很大,就会形成网页的卡顿,掉帧等状况。

var bstyle = document.body.style; // cache
 
bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // 再一次的 reflow 和 repaint
 
bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint
 
bstyle.fontSize = "2em"; // reflow, repaint
 
// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('dude!'));

复制代码

以上逻辑,几乎每一步都会形成重排重绘,若是浏览器像这样处理的话,可能现代的浏览器没有咱们使用的那么流畅了。
所以浏览器有一个机制,会把须要重排重绘的先积累着,而后一次性进行重排重绘

固然,不是全部的状况浏览器都是这样处理的,好比resize或者修改默认字体,对于这些操做,浏览器会立马进行重排

因此咱们在监听resize事件时,通常咱们都会作防抖节流

如何减小重排和重绘

  • 尽可能避免style的使用,对于须要操做DOM元素节点,从新命名className,更改className名称。
  • 若是增长元素或者clone元素,能够先把元素经过documentFragment放入内存中,等操做完毕后,再appendChildDOM元素中。
  • 不要常常获取同一个元素,能够第一次获取元素后,用变量保存下来,减小遍历时间。
  • 尽可能少使用dispaly:none,可使用visibility:hidden代替,dispaly:none会形成重排visibility:hidden会形成重绘
  • 不要使用Table布局,由于一个小小的操做,可能就会形成整个表格的重排重绘
  • 使用resize事件时,作防抖节流处理。
  • 对动画元素使用absolute / fixed属性。
  • 批量修改元素时,能够先让元素脱离文档流,等修改完毕后,再放入文档流。

最后

参考文章:

How browsers work

浏览器的渲染原理简介

前端性能优化之重排和重绘

相关文章
相关标签/搜索