浏览器的大概工作流程
以普通的HTML页面为例:
- 解析HTML文档,生成dom树
- 解析css产生css规则树
- 解析JavaScript,通过DOM-API来操作dom树和css规则树
- 通过dom树和css规则树来构造渲染树(rendering tree)
- 调用操作系统的GUI接口画页面
回流(reflow)和重绘(repaint)
回流:
元素的大小尺寸、位置发生变化时,会重新计算渲染树,页面要进行重新排版工作,这个过程即是回流。<br>
重绘:
元素做了一些不影响排版的改变,比如背景色、下划线等等,只需要重新绘制的过程,叫做重绘。
显然回流带来的代价大于重绘,因为重绘仅仅是重新画一遍元素而已,但是重绘是重新计算+重新画。
回流的原因:
- Initial。网页初始化的时候。
- Incremental。一些Javascript在操作DOM Tree时。
- Resize。其些元件的尺寸变了
- StyleChange。如果CSS的属性发生变化了。
- Dirty。几个Incremental的reflow发生在同一个元素的子树上。
更具体的说,就是这些常见的操作会引起回流:
- 调整窗口大小
- 字体大小
- 样式表变动
- 元素内容变化,尤其是输入控件
- CSS伪类激活,在用户交互过程中发生
- DOM操作,DOM元素增删、修改
- width, clientWidth, scrollTop等布局宽高的计算
ps:但是浏览器并不会在我们一进行上面的操作就进行回流,浏览器会积攒一批reflow然后一起进行回流,不过有的操作会让浏览器立马进行回流,比如resize窗口,改变了页面默认的字体,或者说获取以下这些值:
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- IE中的 getComputedStyle(), 或 currentStyle
如何减少reflow和repaint
- 避免频繁的修改样式,可以将要修改的多个样式定义为一个class类,然后将类名一次赋值即可
把dom离线操作:
- 使用documentFragment 对象在内存里操作DOM
- 先把DOM给display:none(有一次reflow),然后你想怎么改就怎么改。比如修改100次,然后再把他显示出来。
- clone一个DOM结点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下
- 不要把DOM结点的属性值放在一个循环里当成循环里的变量。不然这会导致大量地读写这个结点的属性。
- 为动画的HTML元件使用fixed或absoult的position,那么修改他们的CSS是不会reflow的,因为脱离了文档流