重排reflow
和重绘repaint
1.重排reflow
reflow
指的是重新计算页面布局
某个节点reflow
时会重新计算节点的尺寸和位置,而且还有可能触发其子节点,祖先节点和页面上的其他节点reflow
,在这之后再触发一次repaint
;
当render tree
中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就成为回流;
每个页面至少需要一次回流,就是在页面第一次加载的时候;
1.1导致reflow
的操作有:
1.调整窗口的大小;
2.改变字体;
3.增加或者移除样式表;
4.内容发生变化,比如input中输入文字;
5.激活css
伪类,如:hover
(IE中为兄弟节点伪类的激活);
6.操作class
属性;
7.脚本操作DOM
;
8.计算offsetWidth
和offsetHeight
属性;
1.2触发页面重新布局的一些css属性
1.2.1 盒子模型相关属性会触发重新布局
width
,height
,padding
,margin
,display
,border-width
,border
,min-height
1.2.2 定位属性及浮动也会触发重新布局
top
,bottom
,left
,right
,position
,float
,clear
1.2.3 改变节点内部文字结构也会触发重布局
text-align
, overflow-y
,font-weight
,overflow
,font-family
,line-height
,white-space
,font-size
2.重绘repaint
repaint
或者redraw
遍历所有的节点检测各个节点的可见性,颜色,轮廓,等可见的样式属性,然后根据检测的结果重新更新页面的响应部分;
当render tree
中的一些元素需要更新属性,而这些属性只会影响元素的外观,风格,而不会影响布局的,比如background-color
,被称为重绘;
2.1 只会触发重绘不触发重排的一些css属性:
color
,
border-style
,border-radius,
visibility
,
text-decoration
,
background
,background-image
,background-position
,background-repeat
,background-size
outline
,outline-color
,outline-style
,outline-width
box-shadow
var bstyle = document.body.style; // cache
bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // 再一次的 reflow 和 repaint
bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint
bstyle.fontSize = "2em"; // reflow, repaint
// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('dude!'));
注意: 每修改一次样式,他就会reflow
或者repaint
一次,一般来说,浏览器会把这样的操作积攒一批,然后做一次reflow
,这又叫异步reflow
或者增量异步reflow
,但是有些情况浏览器不会这样,例如:resize
窗口,改变页面的默认字体,这些操作,页面会了立马进行reflow
;
3.减少重排和重绘
重绘和回流在实际开发中很难避免,要尽量减少这种行为发生;
1.js
尽量少访问dom
节点和css
属性,尽量不要过多的频繁去增加,修改,删除元素,这样可能会频繁的导致页面reflow
,可以先把该dom
节点抽离到内存中进行复杂的操作然后在display
到页面上,(需要DOM
)
2.减少不必要的DOM
层级(DOM depth
),改变DOM
树中的一级会导致所有层级改变,上至根部,下至改变节点的子节点,这导致大量时间耗费在执行reflow
上面;
3.不要通过父级来改变元素样式,最好直接改变子元素样式,改变子元素样式尽可能不影响父级元素和兄弟元素的大小和尺寸;
4.尽量通过class
来设计元素样式,切忌用style多次操作单个属性;
5.尽可能的为产生动画的HTML
元素使用fixed
或absolute
的position
,那么修改他们的css
是不会reflow
的;
6.img
标签要设置宽高,以减少重排和重绘;
7.把DOM
离线后修改,如将一个dom
脱离文档流,如display:none
,在修改属性,这里只发生一次回流;
8.尽量用transform
来做形变和位移,不会造成回流;
9.权衡速度的平滑,比如实现一个动画,以1个像素为单位的位移这样最平滑,但是reflow
就会过于频繁,CPU
很快就会被完全占用,如果以3个像素为单位移动就会好很多;
10.不要用tables
布局的另一个原因就是tables
中某个元素一旦触发reflow
就会导致table
里所有的其他元素reflow
,在适合用tables
的场合,可以设置table-layout
为auto
或fixed
;
11.避免不必要的复杂的css
选择器,尤其是后代选择器(descendant selectors
),因为为了匹配选择器将耗费更多的CPU
;
注意: display:none
会触发reflow
,而visibility:hidden
只会触发repaint
,因为没有发现位置变化;
总结:
1. 重排:元素的尺寸变化,位置变化;
2. 重绘:元素的颜色,背景,边框,轮廓变化,但是元素的几何尺寸没有变;
3. `reflow`的成本比`repaint`成本高的多的多,`DOM Tree`里的每个节点都会有`reflow`方法,一个节点的~很可能会导致子节点,甚至父节点以及同级节点的`reflow`,在一些高性能的电脑上也许还没什么,但是如果`reflow`发生在手机上,那么这个过程是非常痛苦和耗电的;