重绘回流(重排)

Posted 水香木鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重绘回流(重排)相关的知识,希望对你有一定的参考价值。

什么是重绘?回流(重排)?

  1. 当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流。每个页面至少需要一次回流,就是在页面第一次加载的时候。
  2. 当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
    注:回流必将引起重绘,而重绘不一定会引起回流。

什么是重绘?回流(重排)?

—不同的条件下发生重排的范围及程度会不同 :

  1. 页面初始渲染

  2. 改变字体,改变元素尺寸(宽、高、内外边距、边框,改变元素位置等
    各种情况:
    设置 style 属性的值
    激活 CSS 伪类,比如 :hover
    操作 class 属性
    css3的某些属性(https://csstriggers.com/ 结合此链接查看哪些属性会触发重排、哪些属性会触发重绘以及哪些属性会触发合成;)
    (注意:如果修改属性不影响布局则不会发生重排)

  3. 改变元素内容(文本或图片等或比如用户在input框中输入文字)

  4. 添加/删除可见DOM元素
    (注意:如果是删除本身就display:none的元素不会发生重排;visibility:hidden的元素显示或隐藏不影响重排)

  5. fixed定位的元素,在拖动滚动条的时候会一直回流

  6. 调整窗口大小(Resizing the window)

  7. 计算 offsetWidth 和 offsetHeight 属性
    【注释2】
    【注释2:flush队列】

浏览器是聪明的,当对以下属性进行操作的时候:
包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)。

浏览器不会马上操作它们,而是会先缓存在队列中,有一定时间顺序去执行这些操作,但是在这过程中我们需要去获取在该队列中的属性时,浏览器为取得正确的值就会触发重排。这样就使得浏览器的优化失效了。
所以,在多次使用这些值时应进行缓存。

如何减少回流,重绘?

  1. 修改html元素中对应的class名,利用class替换样式
    【代码示例】
<style type = "text/css" >
.changeStyle{width: 200px;height: 200px;}
</style >
< script type = "text/javascript" >
    $(document).ready(function ()
    {
        var el = $('id');
        //1
       el.css('width', '200px');
       el.css('height', '200px');
        //2
       el.css({
            'width' : '200px;',
            'height' : '200px;'
        });
        //3 
       el.addClass('changeStyle');
    });
</script >
  1. csstext(利用cssText属性合并所有改变,然后一次性写入)
    【代码示例】
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!));

// 不好的写法
var left = 1;
var top = 1;
el.style.left = left + "px";
el.style.top = top + "px";
// 比较好的写法 
el.className += " className1";
// 比较好的写法 
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
  1. display:none(隐藏元素,应用修改,重新显示)
    【代码示例】
var list = document.getElementById("list");
list.style.display = 'none’;
appendDataToElement(list,data);
list.style.display = 'block';
  1. cloneNode (将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换回去; )
    【代码示例】
var old = document.getElementById("list");
var clone = old.cloneNode(true);
appendDataToElement(clone,data);
old.parentNode.replaceChild(clone,old);
  1. document.createDocumentFragment();
    (使用文档片段(document fragment)在当前DOM之外构建一个子树,再插回去)
    【代码示例】
var fragment = document.createDocumentFragment();
var list = document.getElementById("list");
for (var i = 0; i< 10; i++)
{
    var _li = document.createElement("li");
    _li.onmouseover = function ()
    {
       this.style.backgroundColor = "#22b909";
       this.style.width = "120px";
       this.style.height = "50px";
    }
    _li.onmouseout = function ()
    {
       this.style.backgroundColor = "";
       this.style.width = "100px";
       this.style.height = "40px";
    }
   fragment.appendChild(_li);
}
list.appendChild(fragment);
  1. 使用trsansform
    > CSS的最终表现分为以下四步:Recalculate Style -> Layout -> Paint Setup and Paint -> Composite Layers
    按照中文的意思大致是 查找并计算样式 -> 排布 -> 绘制 -> 组合层。

    由于transform是位于Composite Layers层,而width、left、margin等则是位于Layout层,在Layout层发生的改变必定导致Paint Setup and Paint -> Composite Layers,
    所以相对而言使用transform实现的动画效果肯定比使用改变位置(margin-left等)这些更加流畅。
    

以上是关于重绘回流(重排)的主要内容,如果未能解决你的问题,请参考以下文章

重绘重排(回流)

前端性能-重绘和重排(回流)

重绘重排(回流)

重绘回流(重排)

重绘回流(重排)

重排和回流