2

对于页面重排(回流)和重绘一直有个模糊的概念,今天整理一下。

请看下图,我们知道在页面加载的时候,浏览器解析html,构建DOM tree。解析样式表,构建Css tree。两个合并为Render tree。Render tree构建完成后,浏览器就开始布局(layout)和绘制(painting)了, 最后将页面展示出来,layout和painting也即是渲染的过程。

clipboard.png

以下三种情况,会导致网页重新渲染。

  • 修改DOM
  • 修改样式表
  • 用户事件(比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)

重新渲染,就需要重新生成布局和重新绘制。前者叫做"重排/回流"(reflow),后者叫做"重绘"(repaint)。重排一定会触发重绘,重绘不一定触发重排(比如元素的背景发生变化)。

哪些情况会触发重排呢?

  • 元素的显示和隐藏;
  • 元素大小位置的改变;
  • 元素内容的变化;
  • 浏览器窗口的变化;
  • 页面初始化;

如何避免重排?(前端性能优化的一部分)
1.多次样式的修改合并为一次;

//错误写法
var dom = document.getElementById('div')
dom.style.width = '100px'
dom.style.height= '100px'
//这里会导致触发页面两次重排

//正确写法
// css
.class{
    width:100px;
    height:100px;
}
var dom = document.getElementById('div')
dom.className = 'class'

//正确写法
var dom = document.getElementById('div')
dom.style.cssText = 'width: 100px; height: 100px;'

2.脱离文档流

var dom = document.getElementById('div')
dom.style.display = 'none'
dom.style.width = '100px'
dom.style.height= '100px'
dom.style.padding = '5px';
dom.style.display = 'block'

3.使用createElementFragment来一次性插入

var dom = document.getElementById('div')
var fragment = document.createDocumentFragment()
// 往 fragment里添加元素,一次性添加到真实的DOM里
dom.appendChild(fragment)

4.缓存布局信息

current = div.offsetLeft;
div.style.left = 1 + current + 'px';
div.style.top = 1 + current + 'px';

5.使用虚拟DOM的框架vue/react等
6.使用window.requestAnimationFrame() 与 window.requestIdleCallback() 优化渲染。

参考:
https://segmentfault.com/a/1190000016990089


pwk901204
0 声望0 粉丝

工作使我快乐, 微笑~~