浏览器渲染原理
工作流程
1.浏览器解析三个东西
- 解析HTML/SVG/XHTML,webkit有3个C++的类对应这三个文档,解析以后会生成一个DOM tree
- css,解析css会生成css的rule tree
- js,通过DOM API,CSSOM API来操作
2.解析完成后,浏览器会通过DOM Tree和Css rule tree来构造rendering tree
- Rendering Tree 渲染树并不等同于Dom树,因为像display:none这种东西没必要存在到rendering tree中
- css rule tree 是为了把css匹配到每一个rendering tree的element上,也就是所谓的frame
- 然后计算每个frame的位置,这叫做layout和reflow的过程
3.最后通过操作系统的native GUI的API绘制
渲染
渲染流程
- 计算css样式
- 构建rendering tree
- Layout:定位坐标的大小,是否换行,各种position,overflow,z-index属性
- 正式开画
重新渲染
- repaint:屏幕的一部分要重画,比如某得css的背景色变了,但是元素的尺寸没有变
- reflow:意味着元件的几何尺寸变了,我们需要重新验证并计算render tree。
html使用的是flow base layout ,也就是流式布局,所以,如果某元件的尺寸发生了变化,就需要重新布局,reflow会从<html>这个root frame 开始递归往下
渲染成本
- reflow的成本比repaint的成本高的多,Dom tree里的每个节点都会有reflow方法,一个节点的reflow可能导致子节点,甚至父节点以及同级节点的reflow。
以下动作会引起渲染成本增高
- 当你增加,删除,修改dom节点时,会导致repaint或reflow
- 当你移动dom位置,或是搞个动画
- 当你修改css样式的时候
- 当你的resize窗口的时候,或是滚动的时候
- 当你修改网页默认字体的时候
- 注:display:none 会发生reflow,而visibility:hidden只会触发repaint,因为没有位置发生改变。
- 滚屏的时候如果有position:fixed的时候,滚动浏览器是一个相当痛苦的过程。因为滚屏都可能造成reflow
造成reflow的原因
- inital
- incremental:js操作dom
- resize:某些元素的尺寸变化
- styleChange:css的属性发生变化
- Dirty:几个incremental的reflow发生在同一个frame的子树上
1 |
|
当然浏览器不会每次改一次样式,就reflow或repaint一次,一般来说,它会把这样的操作积攒,然后做一次reflow,这叫异步的reflow或者增量异步reflow,但是有些情况并不会这么做,比如:resize窗口,改变了页面默认的字体,这些操作会马上进行reflow
减少reflow/repaint
- 1.不要一条一条的修改dom的样式,先定义好css的class,然后修改dom的className
2.把dom离线后修改
使用documentFragment对象在内存里操作dom,documentFragements是一些dom节点,他们不是dom树的一部分,创建一个文档片段,然后将创建的dom元素插入到文档片段中,最后把文档片段插入到dom中,因为文档片段存在于内存中,并不在dom树中,所以将子元素插入到文档片段不会引起页面回流
1
2
3
4
5
6
7
8
9
10
11var ul = document.getElementByTagName('ul')[0];
var docfrag = document.createDocumentFragment();
var ss = ['asdsa', 'ssss', 'sssssdsd'];
ss.foreach(function(e) {
var li = document.createElement('li');
li.textContent = e;
docfrag.appendChild(li);
})
ul.appendChild(docfrag);不要把dom节点的属性值放在一个循环里当成循环的变量,会导致大量的读写这个节点的属性。
- 尽可能的修改层级比较低的dom
- 为动画的html原件使用fixed或absulote,修改他们的css不会reflow
- 千万不要使用table布局,一个小改动会造成整个table重新布局
此文为总结文,可以查看原文,原文有很多很棒的信息
点此查看原文