重绘(repaint)与重排(reflow)

当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为reflow。

什么时候引起重排?

1.页面渲染初始化

2.DOM树的结构改变

包括了:

  • 添加或者删除DOM结点
  • 元素内容变化(文字的数量、文字的大小、图片的大小、图片的更换)

3.render树变化

  • 元素尺寸或位置发生改变(如padding的修改)
  • display属性改为可见。
  • 激活CSS伪类(例如::hover)

4. 浏览器窗口大小发生改变(resize事件触发)

5. 最复杂的一种:获取某些属性,引发回流很多浏览器会对回流做优化,他会等到足够数量的变化发生,在做一次批处理回流。offsetHeight属性需要返回最新的布局信息,因此浏览器不得不执行渲染队列中的“待处理变化”并触发重排以返回正确的值。

  • offsetTop, offsetLeft, offsetWidth, offsetHeight
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • width,height
  • 调用了getComputedStyle(), 或者 IE的 currentStyle

回流一定伴随着重绘,而重绘却可以单独出现

减少回流?

  • 避免逐项更改样式。最好一次性更改style属性,或者将样式列表定义为class并一次性更改class属性。
// 不推荐的写法:

var ele = document.getElementById('myDiv');
ele.style.borderLeft = '1px';
ele.style.borderRight = '2px';
ele.style.padding = '5px';

// 推荐的写法:

var ele = document.getElementById('myDiv');
// 1. 重写style
ele.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';
// 2. add style
ele.style.cssText += 'border-left: 1px;'
// 3. use class
ele.className = 'active';
  • 避免循环操作DOM。创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document。
//创建轻量级文档片段
var fragment = document.createDocumentFragment();
 
//将要加的子节点写在fragment上
var li = document.createElement('li');
li.innerHTML = 'apple';
fragment.appendChild(li);
 
var li = document.createElement('li');
li.innerHTML = 'watermelon';
fragment.appendChild(li);
 
//当附加一个fragment到父节点时,实际上被添加的是该fragment的子节点,而不是片断本身
document.getElementById('fruit').appendChild(fragment);
  • 避免多次读取offsetLeft等属性。无法避免则将它们缓存到变量。
  • 将复杂的元素(如动画)绝对定位或固定定位,使它脱离文档流。否则回流代价十分高

display:none和visibility:hidden会产生回流与重绘吗?

display:none指的是元素完全不陈列出来,不占据空间,涉及到了DOM结构,故产生reflow与repaint

visibility:hidden指的是元素不可见但存在,保留空间,不影响结构,故只产生repaint

参考:
深入理解浏览器的重绘与重排

你可能感兴趣的:(重绘(repaint)与重排(reflow))