浏览器中的回流,重绘

2,225 阅读3分钟

回流(reflow)是页面中元素的尺寸,布局,隐藏或重新构建,这个称为回流(回流会阻塞用户在浏览器中的操作)。因为回流可能导致整个dom树的重新构造,所以是性能的一大杀手。回流必将引起重绘,而重绘不一样引起回流。但是回流是自上而下的,所以下不触犯上,我们可以在最后面修改信息,这样对全局影响较少。


参考网站

浏览器内核渲染引擎渲染原理

页面重绘和回流以及优化


回流何时发生

    1.添加或删除DOM元素
    2.元素位置改变
    3.元素尺寸改变(边距,填充,边框,宽度,高度)
    4.元素内容改变(文本改变,图片大小改变而引起的计算值和高度改变)
    5.页面渲染初始化
    6.浏览器窗口改变(resize触发时)
    7.fixed定位的元素,在拖动滚动条的时候会一直回流
    8.offset相关属性计算
    9.设置style的值

重绘

说白了就是更改元素的背景颜色,字体颜色一类的,重绘只影响元素的外观,风格,其不影响布局


如何减少回流、重绘

var s = document.body.style; 

s.padding = "2px"; // 回流+重绘

s.border = "1px solid red"; // 再一次 回流+重绘

s.color = "blue"; // 再一次重绘

s.backgroundColor = "#ccc"; // 再一次 重绘

s.fontSize = "14px"; // 再一次 回流+重绘

// 添加node,再一次 回流+重绘
document.body.appendChild(document.createTextNode('abc!'));

避免回流

一. CSS中避免回流

1.尽可能在DOM树的最末端改变class
2.避免设置多层内联样式
3.动画效果应用到position属性为absolute或fixed的元素上
4.牺牲平滑度换取速度
5.避免使用table布局
6.避免使用CSS的JavaScript表达式

二. JS操作避免回流

1.避免逐项更改样式。最好一次性更改style属性,或者将样式列表定义为class并一次性更改class属性。
2.避免循环操作DOM。创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document。
3.也可以在一个display:none的元素上进行操作,最终把它显示出来。因为display:none上的DOM操作不会引发回流和重绘。(visibility: hidden占位,所以会造成回流)
4.避免循环读取offsetLeft等属性。在循环之前把它们存起来。
5.绝对定位具有复杂动画的元素。绝对定位使它脱离文档刘,否则会引起父元素及后续元素大量的回流。

借鉴来源

面试:页面加载海量数据

很多数据时需要进行操作大量的DOM,可以使用以下方法(避免回流和重绘) createDocumentFragment()

function addDivs(element) {
  var div;
  // Creates a new empty DocumentFragment.
  var fragment = document.createDocumentFragment();
  for (var i = 0; i < 20; i ++) {
    div = document.createElement('a');
    div.innerHTML = 'Heya!';
    fragment.appendChild(div);
  }
  element.appendChild(fragment);
}

window.requertAnimationFrame(addDivs)

页面重绘时,会通知window.requertAnimationFrame

具体可查看

requestAnimationFrame还有毛线用?

优点:

 1.将每一帧的DOM操作(回流,重绘,重排)集中起来,在一次回流或重绘中完成
 2.CPU,GPU,内存使用量低
 3.页面不激活,方法不调用

如有问题,请及时反馈。