浏览器运行机制图:css
浏览器的运行机制:layout:布局;node
一、构建DOM树(parse):渲染引擎解析HTML文档,首先将标签转换成DOM树中的DOM node(包括js生成的标签)生成内容树(Content Tree/DOM Tree);后端
二、构建渲染树(construct):解析对应的CSS样式文件信息(包括js生成的样式和外部css文件),而这些文件信息以及HTML中可见的指令(如<b></b>),构建渲染树(Rendering Tree/Frame Tree);浏览器
三、布局渲染树(reflow/layout):从根节点递归调用,计算每个元素的大小、位置等,给出每一个节点所应该在屏幕上出现的精确坐标;缓存
四、绘制渲染树(paint/repaint):遍历渲染树,使用UI后端层来绘制每一个节点。app
重绘(repaint或redraw):当盒子的位置、大小以及其余属性,例如颜色、字体大小等都肯定下来以后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈如今页面上。布局
重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性从新绘制,使元素呈现新的外观。字体
触发重绘的条件:改变元素外观属性。如:color,background-color等。优化
注意:table及其内部元素可能须要屡次计算才能肯定好其在渲染树中节点的属性值,比同等元素要多花两倍时间,这就是咱们尽可能避免使用table布局页面的缘由之一。动画
重排(重构/回流/reflow):当渲染树中的一部分(或所有)由于元素的规模尺寸,布局,隐藏等改变而须要从新构建, 这就称为回流(reflow)。每一个页面至少须要一次回流,就是在页面第一次加载的时候。
重绘和重排的关系:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并从新构造这部分渲染树,完成回流后,浏览器会从新绘制受影响的部分到屏幕中,该过程称为重绘。
因此,重排一定会引起重绘,但重绘不必定会引起重排。
触发重排的条件:任何页面布局和几何属性的改变都会触发重排,好比:
一、页面渲染初始化;(没法避免)
二、添加或删除可见的DOM元素;
三、元素位置的改变,或者使用动画;
四、元素尺寸的改变——大小,外边距,边框;
五、浏览器窗口尺寸的变化(resize事件发生时);
六、填充内容的改变,好比文本的改变或图片大小改变而引发的计算值宽度和高度的改变;
七、读取某些元素属性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE) )
重绘重排的代价:耗时,致使浏览器卡慢。
优化:
一、浏览器本身的优化:浏览器会维护1个队列,把全部会引发回流、重绘的操做放入这个队列,等队列中的操做到了必定的数量或者到了必定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让屡次的回流、重绘变成一次回流重绘。
二、咱们要注意的优化:咱们要减小重绘和重排就是要减小对渲染树的操做,则咱们能够合并屡次的DOM和样式的修改。并减小对style样式的请求。
(1)直接改变元素的className
(2)display:none;先设置元素为display:none;而后进行页面布局等操做;设置完成后将元素设置为display:block;这样的话就只引起两次重绘和重排;
(3)不要常常访问浏览器的flush队列属性;若是必定要访问,能够利用缓存。将访问的值存储起来,接下来使用就不会再引起回流;
(4)使用cloneNode(true or false) 和 replaceChild 技术,引起一次回流和重绘;
(5)将须要屡次重排的元素,position属性设为absolute或fixed,元素脱离了文档流,它的变化不会影响到其余元素;
(6)若是须要建立多个DOM节点,可使用DocumentFragment建立完后一次性的加入document;
var fragment = document.createDocumentFragment(); var li = document.createElement('li'); li.innerHTML = 'apple'; fragment.appendChild(li); var li = document.createElement('li'); li.innerHTML = 'watermelon'; fragment.appendChild(li); document.getElementById('fruit').appendChild(fragment);
(7)尽可能不要使用table布局。