
Contents
在讨论今天的主角之前,我们要先了解一下浏览器的渲染机制。以Google,Firefox,Safari为例,Firefox 使用Geoko——Mozilla 自主研发的渲染引擎,Safari 和Chrome 都使用 webkit。
我们主要以 Webkit的主流程为例
HTML 生成 DOM 树CSS 生成CSSOM 规则树DOM 树与 CSSOM 规则树合并在一起生成渲染树Render Tree上面我们知道,我们会根据 Render Tree 去遍历渲染,所以当我们的节点发生改变时,浏览器重新渲染部分节点或者全部文档,我们称这个过程为回流
大致整理会导致回流的一些操作
主要有下面几个API
盒子操作相关
elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight, elem.offsetParentelem.clientLeft, elem.clientTop, elem.clientWidth, elem.clientHeightelem.getClientRects(), elem.getBoundingClientRect()滚动相关
elem.scrollBy(), elem.scrollTo()elem.scrollIntoView(), elem.scrollIntoViewIfNeeded()elem.scrollWidth, elem.scrollHeightelem.scrollLeft, elem.scrollTop其他
上述主要是我们经常使用的一些API,其他还有一个api已经有热心网友帮我们整理出来了
我们可以看一下
当我们操作的节点上的元素并不导致元素位置发生变化时,比如color,background-color,visibility(注意虽然节点隐藏了,但是元素还在,并且位置也不会发生变化)
浏览器会将新的样式赋值给这些节点,我们称这个过程为重绘
按照常理也很好理解,因为位置,大小等发生的回流操作相比于仅仅是颜色的变化,带给我们的视觉直观感受来说,回流是比较大的。
事实上,回流确实比重绘的成本更大,并且有时候并不是只回流一个元素,甚至会带动父元素或者子元素一起回流。
现代浏览器会对频繁的回流或重绘操作进行优化,浏览器会维护一个队列,当我们页面发生回流或重绘时,有时候并不是立即执行,而是先放入维护的队列中,到达一定时间后统一去进行绘制
当你访问以下属性或方法时,浏览器会立刻清空队列
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft`
scrollWidth、scrollHeight、scrollTop、scrollLeft
width、height
getComputedStyle()
getBoundingClientRect()
所以当我们需要使用如上api获取数据时,我们要注重渲染时机以及取值时机
table 布局。DOM 树的最末端改变class。position属性为absolute或fixed的元素上。CSS表达式(例如:calc())。style属性,或者将样式列表定义为class并一次性更改class属性。
-避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。我们把页面文档比作一个积木的话,我们抽离中间或者底部的一个积木块,我们的积木会重新找到重心并且稳固下来,我们把这个过程称之为回流
我们在某个积木上涂上颜色,这并不会造成整个积木的稳定,我们把这个过程叫做重绘
或者说,我们简单理解会引起元素位置变化的就会reflow,会引起位置变化的,只是在以前的位置进行改变背景颜色等,只会repaint