由网页渲染提出的优化建议

总所周知,网页加载渲染分为一下几个阶段:

-构建dom树(dom tree)

从上到下解析html构建dom树,也叫内容树

-构建css树(CSSOM)

将css样式附着到dom树上生成CSSOM tree(css object model tree)

-执行js

执行js代码(同步)

-构建渲染树(rebder tree)

渲染树代表一个稳定的视觉呈现,有一系列矩形构成,带有大小、颜色、字体等属性,

这一个个小矩形,firefox称为框架(frame),webkit称为渲染对象(render object)

-布局(layout)

计算渲染对象的位置并布局到页面上

-绘制(paint)

为节点添加样式,比如颜色、边框

当我们改变节点样式,如果引起位置改变,会触发回流(reflow),引起颜色、字体等改变,会触发重绘(repaint),常见情况如下:

回流:

DOM操作,例如增加、删除、移动

窗口变化

添加伪类

变更内容(例如输入框改变文本)

访问、修改css属性(注意访问css属性也会引发回流!)

重绘

改变元素样式,颜色、背景色等

接下来看一个例子:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .slide-left {
                -webkit-transition: margin-left 1s ease-out;
                -moz-transition: margin-left 1s ease-out;
                -o-transition: margin-left 1s ease-out;
                transition: margin-left 1s ease-out;
            }
            
        </style>
    </head>
    <body>
        <div class="a">111</div>
    </body>
    <script src="js/jquery.min.js"></script>
    <script>
        var a = $('.a');
        a.css({"margin-left": "100px"}); //第一次
        a.addClass('slide-left');
        $('.slide-left').css({"margin-left": "10px"}); //第二次
    </script>
</html>

根据回流触发条件,这会触发两次回流,预计将看到a的margin-left将0-->100-->10的变化过程,但是我们只看到0-->10的变化,为什么呢?

因为浏览器为了减少reflow次数,会在内部设置一个缓存队列,将需要reflow、repaint的操作放入队列并覆盖前面的操作,当一定的时间间隔会达到一定大小时再进行操作, clever blowser~~

但是,很多时候我们都会无意中触发强制重绘

例如对上面的代码作出如下修改:

var a = $('.a');
a.css({"margin-left": "100px"});
a.css({"margin-left"});
a.addClass('slide-left');
$('.slide-left').css({"margin-left": "10px"});

我们将看到a的margin-left将0-->100-->10的变化过程,因为当我们向浏览器请求style信息时,浏览器为了获得当前最精准的位置,会立刻强制重绘!

优化建议:

1.html文档层次越少越好,不要高于六层

2.js不要放在head里头,尽量后方,因为其加载和执行是同步的,会阻塞之后的操作

3.减少、避免强制重绘

4.用添加class代替多个js直接操作dom,减少reflow、repaint次数

5.动画元素设为absolute或fixed,以免对齐改变时引起大规模的reflow

6.隐藏在屏幕外或者当屏幕滚动时停止动画,减少reflow

7.减少reflow次数,可利用虚拟dom、克隆节点(cloneNode)到内存中,或预先将元素设为display: none,操作完毕再呈现

一言以蔽之,就是减少重绘与重排的次数与规模。

最后,再总结一下渲染树与dom树之间的关系

1.不可见的dom元素不会插入渲染树,如display:none, 如head元素

2.dom元素与渲染对象不是一一对应的关系,可能是一对多,例如文本宽度不够折行,新的一行将作为额外的渲染对象,例如select,它代表三个渲染对象:显示区域、下拉列表和选择按钮。

原文地址:https://www.cnblogs.com/yanze/p/7928575.html