zoukankan      html  css  js  c++  java
  • 由网页渲染提出的优化建议

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

    -构建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,它代表三个渲染对象:显示区域、下拉列表和选择按钮。

  • 相关阅读:
    vue
    手写Promise
    Promise应用
    Promise
    JS_URL模块
    模板字符串应用
    JS-OOP
    jQuery——过时,但是经典,关注核心点即可。
    MySql补充
    offset系列
  • 原文地址:https://www.cnblogs.com/yanze/p/7928575.html
Copyright © 2011-2022 走看看