重排和重绘
# 重排和重绘
# 1.重排(Relayout/Reflow)
在弄明白什么是重排之前,我们要知道:浏览器渲染页面默认采用的是流式布局模型(Flow Based Layout),实际就使我们常说的文档流,这一点很重要。
所谓重排,实际上是根据渲染树中每个渲染对象的信息,计算出各自渲染对象的几何信息(DOM对象的位置和尺寸大小),并将其安置在界面中的正确位置。
重排也叫回流,实际上,reflow的字面意思也是回流,之所以有的叫做重排,也许是因为重排更好理解,更符合中国人的思维。
标准文档之所以叫做回流(Reflow),是因为浏览器渲染是基于流式布局的模型,流,当dom或者css几何属性发生改变的时候,文档流会受到波动联动的去更改,流就好比一条河里的水,回流就好比向河里扔了一块石头,激起涟漪,然后引起周边水流受到波及,所以叫做回流,这样理解似乎更标准更规范
由于浏览器渲染界面是基于流式布局模型的,也就是某一个DOM节点信息更改了,就需要对DOM结构进行重新计算,重新布局界面,再次引发回流,
只是这个结构更改程度会决定周边DOM更改范围,即全局范围和局部范围
全局范围就是从根节点html开始对整个渲染树进行重新布局,例如当我们改变了窗口尺寸或方向或者是修改了根元素的尺寸或者字体大小等;而局部布局可以是对渲染树的某部分或某一个渲染对象进行重新布局。
在此,总结会引起重排的操作有:
- 页面首次渲染。
- 浏览器窗口大小发生改变。
- 元素尺寸或位置发生改变。
- 元素内容变化(文字数量或图片大小等等)。
- 元素字体大小变化。
- 添加或者删除可见的DOM元素。
- 激活CSS伪类(例如::hover)。
- 设置style属性
- 查询某些属性或调用某些方法。
常见引起重排属性和方法 | |||
---|---|---|---|
width | height | margin | padding |
display | border | position | overflow |
clientWidth | clientHeight | clientTop | clientLeft |
offsetWidth | offsetHeight | offsetTop | offsetLeft |
scrollWidth | scrollHeight | scrollTop | scrollLeft |
scrollIntoView() | scrollTo() | getComputedStyle() | |
getBoundingClientRect() | scrollIntoViewIfNeeded() |
# 2.重绘(Repainting)
相比重排,重绘就简单多了,所谓重绘,就是当页面中元素样式的改变并不影响它在文档流中的位置时,例如更改了字体颜色,浏览器会将新样式赋予给元素并重新绘制的过程称。
常见引起浏览器绘制过程的属性包含:
color | border-style | visibility | background |
text-decoration | background-image | background-position | background-repeat |
outline-color | outline | outline-style | border-radius |
outline-width | box-shadow | background-size |
# 3.性能优化
我们知道操作DOM是一个高成本的操作,不仅是因为本身js与DOM的链接访问,还包括操作DOM后悔引起一连串的连锁反应(重排),因此,从性能优化角度,我们可以从以下几个方面着手:
# 1.减少DOM操作
最小化DOM访问次数,尽量缓存访问DOM的样式信息,避免过度触发回流。
如果在一个局部方法中需要多次访问同一个dom,则先暂存它的引用。
采用更优的API替代消费高的api,转换优化消费高的集合
用querySelectorAll()替代getElementByXX()。
开启动画的GPU加速,把渲染计算交给GPU。
少用HTML集合(类数组)来遍历,因为集合遍历比真数组遍历耗费更高。
用事件委托来减少事件处理器的数量。
现在大多数框架都采用虚拟dom方式抽象文档树,就是为了减少DOM操作
# 2.减少重排
避免设置大量的style属性,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性
实现元素的动画,它的position属性,最好是设为absoulte或fixed,这样不会影响其他元素的布局
动画实现的速度的选择。比如实现一个动画,以1个像素为单位移动这样最平滑,但是reflow就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。
不要使用table布局,因为table中某个元素旦触发了reflow,那么整个table的元素都会触发reflow。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围
# 3.CSS及动画处理
少用css表达式
减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;
动画尽量使用在绝对定位或固定定位的元素上;
隐藏在屏幕外,或在页面滚动时,尽量停止动画;
ps:更详细的重排和重绘属性可以参考CSS Trigger (opens new window)