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