浏览器渲染过程、回流重绘

渲染引擎

渲染引擎,中文名字非常清晰,就是负责页面渲染的引擎(感觉并没有解释),另一个名词渲染引擎通常也就是浏览器内核,从js拥有了自己的引擎(比如V8)之后,解析JS的工作就从浏览器中独立出来。
简单介绍一下浏览器内核的分类,现如今的主流浏览器以及内核;

浏览器 内核 关系
Chrome Chromium 早期为webkit
FireFox Gecko 开源内核
safari Webkit Chrome内核原型
IE Trident
Edge EdgeHTML 全新引擎
Opera Blink Chromium计划一部分

引擎对HTML的支持不尽相同,所以了解各个浏览器的引擎是什么还是有一定必要的;

渲染过程

浏览器如何组织我们的HTML与CSS并最终形成页面:
1. 加载解析HTML代码,形成DOM TREE;
2. 加载解析CSS代码,形成CSS TREE;
3. 由CSS TREE 与DOM TREE共同构成Rendering Tree,不过Rendering Tree中并不包含在CSS TREE中display:none的标签、<head>标签;
4. 对Rendering Tree 中的元素,开始进行布局计算,通过具有的相应的宽高属性确定每个元素的坐标
5. 最后便是,将我们布局好的元素Paint出来;
下面是一张关于三个树的图,很明显可以看到与展示无关的head标签、title、script等标签与display:none的元素最终不进入Render Tree;

浏览器渲染过程、回流重绘
浏览器渲染简单过程:
浏览器渲染过程、回流重绘

不可绕过的两个问题—Reflow与Repaint

当第一次布局与渲染之后,页面肯定需要与用户产生交互,产生交互就意味着页面需要重新绘制(变红、变蓝)甚至重新布局(缩小了一块区域),这就涉及到两个概念Reflow与Repaint;
Repaint:重绘,重新绘制。repaint 执行过程就是将元素的颜色、背景等属性重新绘制出来,为什么会发生重绘,因为相应区块(div、span……)的边框颜色、背景颜色、字体颜色等发生了改变;
Reflow:回流,重新排版。当页面的元素产生宽高变化,可能占据了其他元素的位置,这时浏览器就需要对页面的布局进行重新的计算,确定元素的坐标,回流发生必定伴随这重绘;

那么什么操作会触发重绘或者回流?

触发重绘:改变元素样式信息,诸如background-color、border-color、 visibility等
触发回流:改变元素的位置信息,宽高信息甚至删除或者添加DOM元素
1. DOM操作(增、删、改,改变DOM排序)
2. 浏览器窗口的操作
3. 内容变化,包括表单域内的文本改变(font-size的改变)
4. 增删样式表内容()
5. 修改class属性
6. 伪类**(:hover、:active)
7. offsetWidth, width, clientWidth, scrollTop/scrollHeight的计算, 会使浏览器将渐进回流队列Flush,立即执行回流。

回流与重绘的影响

最简单的来说,当然是会导致性能不佳了。如果长期操作DOM,产生浏览器的回流(回流必定导致重绘),内核一定是相当忙的要不停地去计算位置、宽高,完了还要去填充像素(重绘)。

优化方向

那么优化方向就是,减少页面的重绘与回流。怎么做?看看谁导致他们回流与重回就知道了。
1. 避免多层样式,已经有class的情况下去添加style属性只会让浏览器多计算一次,多来一次回流,我们应该通过改变class的方法去设置样式(这样也便于管理整体样式不是吗?);
2. 牺牲平滑度换取速度,在操纵移动时,如果每秒移动1px与3px的差距可以忍受,那么用3px,我们的回流与重绘也将大大减少;
3. 避免使用古老的table布局,因为table是个和罕见的可以影响在它们之前已经进入的DOM元素的显示的元素,并且即使一些小的变化将导致table中的所有其他节点回流
4. 在具有fixed、absolute属性的元素上使用动画(OR在动画元素上添加fixed、absolute),他们独自成了自己的文档流,不会影响到主文档流的布局;
5. offsetWidth, width, clientWidth, scrollTop/scrollHeight等值缓存,避免过多访问(DOM元素访问也要缓存);

资料:

  1. So how does the browser actually render a website | JSConf EU 2015 https://www.youtube.com/watch?v=SmE4OwHztCc