细谈页面回流与重绘

你将了解到:css

什么是回流
什么是重绘
回流什么时候发生
重绘什么时候发生
如何避免回流和重绘
复制代码

带着上面的问题,咱们一探究竟前端

什么是回流

回流:英文是reflow浏览器

当render tree中的一部分(或所有),由于元素的规模尺寸、布局、隐藏等改变
而须要从新构建,这就是回流(reflow)
复制代码
  • 每一个页面至少回流一次,即页面首次加载
  • 回流时,浏览器会使渲染树中受到影响的部分失效,并从新构造这部分渲染树
  • 回流完成后,浏览器会从新绘制受影响的部分,是重绘过程

什么是重绘

重绘:英文是repaints缓存

当render tree中的一些元素须要更新属性,而这些属性只是影响元素的外
观、风格,而不影响布局(例如:background-color),则称为重绘(repaints)
复制代码

特色:回流必将引发重绘,重绘不必定引发回流 回流比重绘的代价更高bash

回流什么时候发生

当页面布局和几何属性改变时就须要回流

下述状况会发生浏览器回流:app

(1)添加或者删除可见的DOM元素;
(2)元素位置改变;
(3)元素尺寸改变——边距、填充、边框、宽度和高度
(4)内容改变——好比文本改变或者图片大小改变而引发的计算值宽度和高度改变;
(5)页面渲染初始化;
(6)浏览器窗口尺寸改变——resize事件发生时;
复制代码
let box = document.getElementById("box").style;
box.padding = "2px";   // 回流+重绘
box.border = "1px solid red";  // 再一次 回流+重绘
box.fontSize = "14px";    // 回流+重绘
document.getElementById("box").appendChild(document.createTextNode('abc!'));
复制代码

重绘什么时候发生

元素的属性或者样式发生变化。

let box = document.getElementById("box").style;
box.color = "red";    // 重绘
box.backgroud-color = "blue";    // 重绘
document.getElementById("box").appendChild(document.createTextNode('abc!'));
复制代码

因回流的开销较大,若是每一个操做都去回流重绘的话,浏览器可能就会受不了。因此不少浏览器都会优化这些操做。
布局

屡次的回流、重绘变成一次回流重绘:优化

浏览器会维护1个队列,把全部会引发回流、重绘的操做放入这个队列,等
队列中的操做到了必定的数量或者到了必定的时间间隔,浏览器就会flush
队列,进行一个批处理。
复制代码

可是有时上面的方法会失效,缘由是:动画

有些状况,当请求向浏览器请求一些style信息的时候,就会让浏览器强制flush队列,好比:

(1)offsetTop, offsetLeft, offsetWidth, offsetHeight
(2) scrollTop/Left/Width/Height
(3)clientTop/Left/Width/Height
(4)width,height
(5)请求了getComputedStyle(), 或者 IE的 currentStyle
复制代码

当你请求上面的一些属性的时候,浏览器为了给你最精确的值,须要flush队列,由于队列中可能会有影响到这些值的操做。即便你获取元素的布局和样式信息跟最近发生或改变的布局信息无关,浏览器都会强行刷新渲染队列。ui

这样以来,浏览器的优化就显得力不从心,因此咱们须要一些方法,尽量的避免或减小浏览器的回流、重绘

如何避免、减小回流和重绘

  • 减小对render tree的操做【合并屡次多DOM和样式的修改】
  • 减小对一些style信息的请求,尽可能利用好浏览器的优化策略
(1)添加css样式,而不是利用js控制样式
(2)让要操做的元素进行“离线处理”,处理完后一块儿更新
    当用DocumentFragment进行缓存操做,引起一次回流和重绘
    使用display:none技术,只引起两次回流和重绘
    使用cloneNode(true or false)和replaceChild技术,引起一次回流和重绘
(3)直接改变className,若是动态改变样式,则使用cssText(考虑没有优化的浏览器)
    // bad
    elem.style.left = x + "px";
    elem.style.top = y + "px";
    // good
    elem.style.cssText += ";left: " + x + "px;top: " + y + "px;";
(4)不要常常访问会引发浏览器flush队列的属性,若是你确实要访问,利用缓存
    // bad
    for (var i = 0; i < len; i++) {
      el.style.left = el.offsetLeft + x + "px";
      el.style.top = el.offsetTop + y + "px";
    }
    // good
    var x = el.offsetLeft,
        y = el.offsetTop;
    for (var i = 0; i < len; i++) {
      x += 10;
      y += 10;
      el.style = x + "px";
      el.style = y + "px";
    }
(5)让元素脱离动画流,减小回流的Render Tree的规模
    $("#block1").animate({left:50});
    $("#block2").animate({marginLeft:50});
(6)将须要屡次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其余元素。例若有动画效果的元素就最好设置为绝对定位;
(7)避免使用table布局:尽可能不要使用表格布局,若是没有定宽表格一列的宽度由最宽的一列决定,那么极可能在最后一行的宽度超出以前的列宽,引发总体回流形成table可能须要屡次计算才能肯定好其在渲染树中节点的属性,一般要花3倍于同等元素的时间。
(8)尽可能将须要改变DOM的操做一次完成
    let box = document.getElementById("box").style;
    // bad
    box.color = "red";    // 重绘
    box.size = "14px";    // 回流、重绘
    // good
    box.bord = '1px solid red'
(9)尽量在DOM树的最末端改变class,尽量在DOM树的里面改变class(能够限制回流的范围)
(10)IE中避免使用JavaScript表达式
复制代码

参考资料:

相关文章
相关标签/搜索