浏览器的重绘与回流

DOM操作为什么会影响性能

  • 在浏览器中,DOM 的实现和 ECMAScript 的实现是分离的。比如 在 IE 中,ECMAScript 的实现在jscript.dll中,而 DOM 的实现在 mshtml.dll 中;在 Chrome 中使用 WebKit 中的 WebCore 处理 DOM 和渲染,但ECMAScript 是在 V8 引擎中实现的,其他浏览器的情况类似。所以通过 JavaScript 代码调用 DOM 接口,相当于两个独立模块的交互。相比较在同一模块中的调用,这种跨模块的调用其性能损耗是很高的。但 DOM 操作对性能影响最大其实还是因为它导致了浏览器 的重绘(repaint)和回流(reflow)

浏览器渲染流程

  1. 解析HTML,构建DOM树
  2. 解析CSS,生成CSS规则树
  3. 合并DOM树和CSS规则,生成渲染树
  4. 布局渲染树(Layout/reflow),负责各元素尺寸、位置的计算
  5. 绘制渲染树(paint),绘制页面像素信息

重绘和回流的定义

  • 重绘(Repaint):改变元素外观属性,如:color,background-color 等。
  • 回流(Reflow):当渲染树中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
  • 回流必定会引发重绘,但重绘不一定会引发重绘
  • 重绘回流的代价:耗时,导致浏览器卡慢

导致回流的因素

  • 页面首次渲染(无法避免)
  • 元素尺寸或位置发生改变
  • 浏览器窗口大小发生改变(resize 事件发生时)
  • 元素内容变化(文字数量或图片大小等等)
  • 元素字体大小变化
  • 添加或者删除可见的DOM元素
  • 元素位置的改变,或者使用动画
  • 激活CSS伪类(例如::hover)
  • 查询某些属性或调用某些方法,scrollTo()clientWidthoffsetWidth

优化

CSS
  • 避免使用 table 布局;
  • 将需要多次回流的元素脱离文档流( absolute 或 fixed )
  • 避免使用CSS表达式(例如:calc())。
JS
  • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性;
  • 先为元素设置display: none,操作结束后再把它显示出来;
  • 如果需要创建多个 DOM 节点,可以使用 DocumentFragment 创建完后一次性的加入 document。
    let ul = document.querySelector("ul");
    let fragment = document.createDocumentFragment();

    for (let i = 0; i < 5; i++) {
      let li = document.createElement("li");
      li.innerHTML = i;
      fragment.appendChild(li);
    }
    ul.appendChild(fragment);

你可能感兴趣的:(浏览器的重绘与回流)