浏览器渲染原理
浏览器下载完页面所有的资源后,就要开始构建DOM树,于此同时还会构建渲染树(Render Tree)。(其实在构建渲染树之前,和DOM树同期会构建Style Tree。DOM树与Style Tree合并为渲染树)
1.处理HTML 生成DOM树
2.处理CSS 生成CSSDOM树
3.将两树合并成render 树
4.对render树进行布局计算
5.将render树中的每一个节点绘制到屏幕上
细化分析:
1.浏览器把获取到的html代码解析成1个Dom树,html中的每个tag都是Dom树中的1个节点,根节点就是我们常用的document对象( tag),当然这里包含用js动态创建的dom节点
2浏览器把所有样式(主要包括css和浏览器的默认样式设置)解析成样式结构体,在解析的过程中会去掉浏览器不能识别的样式,生成CSSDOM树
3.DOM tree和CSSDOM tree 合并成 render tree,render tree中每个node都有自己的style,而且render tree不包含隐藏的节点(比如display:none的节点,还有无样式head节点),
因为这些节点不会用于呈现,而且不会影响呈现的,注意 visibility:hidden隐藏的元素还是会包含到render tree中的,因为visibility:hidden 会影响布局(layout),会占有空间。
4.render tree构建完毕之后根据样式计算布局,布局阶段的输出结果称为 “盒模型”(box model)。盒模型精确表达了窗口中每个元素的位置和大小,而且所有的相对的度量单位都被转化成了屏幕上的绝对像素位置 (根据css2的标准,render tree中的每个节点都称为box(Box dimensions----盒子模型),box所有属性:width,height,margin,padding,left,top,border等。)
5.将这些信息渲染为屏幕上每个真实的像素点了。这个阶段称为“绘制”,或者“栅格化”(rasterizing)。
重绘、重排
1.我们计算它们在当前设备中准确的位置和尺寸。
这正是布局阶段要做的的工作,该阶段在英语中也被称为“回流”(reflow),
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。
也会回流(其实我觉得叫重新布局更简单明了些)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
2.重绘(repaints)当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
重绘,重排会影响性能
蓝色:网络通信和HTML解析
黄色:JavaScript执行
紫色:样式计算和布局,即重排
绿色:重绘
触发重排的方法
以下这些属性和方法需要返回最新的布局信息,重新计算渲染树,就会造成回流,
触发重排以返回正确的值。建议将他们合并到一起操作,可以减少回流的次数。
这些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight;
scrollTop、scrollLeft、scrollWidth、scrollHeight;clientTop、clientLeft、
clientWidth、clientHeight;getComputedStyle() 、currentStyle()
提高网页性能,就是要降低"重排"和"重绘"的频率和成本,尽量少触发重新渲染。
DOM变动和样式变动,都会触发重新渲染。但是,浏览器已经很智能了,会尽量把所有的变动集中在一起,排成一个队列,然后一次性执行,尽量避免多次重新渲染.
div.style.color = ‘red’;
div.style.background=‘yellow’;
div.style.left = ’10px’;
div.style.width = ’20px’;
但是浏览器只会触发一次重排和重绘。
一般来说,样式的写操作之后,如果有上面那些属性的读操作,都会引发浏览器立即重排,这种重排,不会形成之前队列优化
div.style.color = ‘red’;
var height = div.offseHeight;
div.style.height = height + ‘px’;
Bad:
div.style.left = div.offsetLeft + ‘px’;
div.style.top = div.offsetTop + ‘px’;
重排重绘两次
Good:
Var left = div.offsetLeft + ‘px’;
Var top = div.offsetTop + ‘px’;
div.style.left = left;
div.style.top = top;
放到队列一次执行重排重绘一次
理论上的解决优化办法
1.说到的,DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。
2.离线操作DOM 如使用隐藏元素 document.createDocumentFragment() cloneNode();
3.修改样式的时候添加类名,或一次性添加到 dom.style.cssText上等