zoukankan      html  css  js  c++  java
  • 浏览器什么时候会引起reflow,应该怎样避免reflow的开销呢?

    在CSS规范中有一个渲染对象的概念,通常用一个盒子(box, rectangle)来表示。mozilla通过一个叫frame的对象对盒子进行操作。frame主要的动作有三个:

    • 构造frame, 以建立对象树(DOM树)
    • reflow, 以确定对象位置,或者是调用mozilla的Layout(这里是指源码的实现)
    • 绘制,以便对象能显示在屏幕上
    总结了在哪些情况下会导致reflow发生:
    • 改变窗囗大小
    • 改变文字大小
    • 添加/删除样式表
    • 内容的改变,如用户在输入框中敲字(这样也会-_-||)
    • 激活伪类,如:hover (IE里是一个兄弟结点的伪类被激活)
    • 操作class属性
    • 脚本操作DOM
    • 计算offsetWidth和offsetHeight
    • 设置style属性
    reflow是不可避免的,只能将reflow对性能的影响减到最小。Nicole提出6点建议:
        • Change classes on the element you wish to style (as low in the dom tree as possible)
          尽可能限制reflow的影响范围。以上面的代码为例,要改变p的样式,class不要加在div上,通过父级元素影响子元素不好。最好直接加在p上。
        • Avoid setting multiple inline styles
          通过设置style属性改变结点样式的话,每设置一次都会导致一次reflow。所以最好通过设置class的方式。
        • Apply animations to elements that are position fixed or absolute
          实现元素的动画,它的position属性应当设为fixed或absolute,这样不会影响其它元素的布局。
        • Trade smoothness for speed
          权衡速度的平滑。比如实现一个动画,以1个像素为单位移动这样最平滑,但reflow就会过于频繁,CPU很快就会被完全占用。如果以3个像素为单位移动就会好很多。
        • Avoid tables for layout
          不要用tables布局的另一个原因就是tables中某个元素一旦触发reflow就会导致table里所有的其它元素reflow。在适合用 table的场合,可以设置table-layout为auto或fixed,这样可以让table一行一行的渲染,这种做法也是为了限制reflow的 影响范围。
        • Avoid JavaScript expressions in the CSS (IE only)
          很多情况下都会触发reflow,如果css里有expression,每次都会重新计算一遍。

    总的来说,reflow就是载入内容树(在HTML中就是DOM树)和创建或更新frame结构的响应的一种过程。

    要提高页面性能,其实就是避免reflow的开销。那么,有哪些方面是需要reflow的呢?比如,未指定图片宽高的话,图片的载入会使页面 reflow, 因为要根据图片宽高来更新frame。这里就有一个提高页面性能的小技巧:如果事先能够确定图片宽高的话,最好在HTML里写上。

    在编写一些常见的动态效果时,一般使用CSS的display来切换可见性。很不幸,这也会产生reflow. 把元素置为display:none,相当于把这个元素的frame销毁了,再置回非none时,需要重新构造frame,这就产生了reflow. 而另外一个切换可见性的属性visibility则不存在reflow问题,置为visibility:hidden的元素的frame并没有销毁,需要 显示的时候其实就是一个绘制(上面提到的动作第三步)过程而已,没有reflow,因此效率会更高。如果你看过一些JavaScript库/框架的源码, 会发现它们大量使用visibility而不是display,道理应该如此。

    移动端fixed元素滑动惯性平滑度

    我们常常遇到这种产品需求,tab标签栏开始固定,当滚动向下超过该标签栏后便会变成fixed元素,一直出现在头部,这样的需求在电脑上没有问题,但是在iPhone5s以下的手机常常会出现小范围错位或者快速移动大范围错位的问题。

    这个时候我们可以引起reflow迫使浏览器重绘以解决这个问题,这里推荐一个奇怪的hack写法:同时设置三个image元素的src属性,便可以全范围解决该难题,  该方案被团队证实并得到应用。

    //三图片src,引发reflow,处理fixed方案惯性问题

    var el = this.els.ctlc.find('img');

    $(el[0]).attr("src", 'http://res.m.ctrip.com/html5/Content/images/144.png');

    $(el[1]).attr("src", 'http://res.m.ctrip.com/html5/Content/images/144.png');

    $(el[2]).attr("src", 'http://res.m.ctrip.com/html5/Content/images/144.png');

    另外,上图中的tab标签下面的蓝线具有动画,但是在小米或者三星手机上可能不会移动,这个时候也可以动态引起reflow解决这个BUG。

    其它

    l  CSS选择器尽量使用id与class,避免过度层叠

    l  避免使用数值,比如:border: none不会引起渲染,而boder: 0会

    l  动画时候让元素脱离文档流,以免导致大量reflow

    l  避免逐条修改DOM样式,改以className实现同样功能

    l  操作DOM时将display设置为none,因为这种元素不会影响渲染,或者操作fragment对象取代操作显示在页面上的DOM

    l  避免将获取DOM样式属性的操作写在循环中,可能引起重复reflow

    我们再来讨论一下重绘与回流的区别:

    前言:什么是重绘与回流?

    重绘(repaints)是一个元素外观的改变所触发的浏览器行为,例如改变vidibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随回流。

    回流(reflow)是更明显的一种改变,可以理解为渲染树需要重新计算。

    1,为什么我们讨厌回流?

         回流这家伙,只要出现,就会重新对DOM树进行渲染,而大多数时候,这种全局性的渲染是无必要的。就像你花钱买了门票去景区玩,进门查票,出门查票,都可 以理解是吧?但是你吃饭也查票,上厕所也查票,就完全没必要了对吧?浏览器虽然不是人,但是没准也有脾气,回流的次数多了,性能跟不上了,就是立马崩溃掉 也是有可能的事儿。回流=查票

    2,我们怎样搞定回流?

    2.1 CSS中的定位、隐藏

       前面说到,回流的危害在于重新对DOM树进行渲染,那么,脱离文档流之后,进行的任何操作,都不会造成回流了!如果有需要经常进行复杂操作的地方,不妨使用position:absolute/fixed定位;或者是display:none,使之脱离文档流后进行操作,操作完成后再进入到文档流之中。

    2.2 CSS中的顽固属性

       以下这些属性,只要是改动了他们的值,就会造成回流,建议将他们合并到一起操作,可以减少回流的次数。这 些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight;scrollTop、scrollLeft、scrollWidth、 scrollHeight;clientTop、clientLeft、clientWidth、 clientHeight;getComputedStyle() 、currentStyle()。

    2.3 Javascript控制样式的最优解

       我们在利用Javascript进行样式控制的时候,不妨只是改变被控制者的class,而非在函数内部直接修改具体的样式。因为浏览器在我们用 Javascript修改每一个具体样式的时候,都会进行一次重绘,如果是修改了2.2中的顽固属性,还会进行回流,这给浏览器造成了巨大的负担。例如, 我们需要用这样的代码:

    坏代码:
    function selectAnchor(element){
    var changeDiv = document.getElementById(element);
    changeDiv.style.color = ‘#093′;
    changeDiv.style.background = ‘#eee’;
    changeDiv.style.height = ’200px’;
    }
     
    好代码:
    CSS:
    changeDiv {
    background: #eee;
    color: #093;
    height: 200px;
    }
    JavaScript:
    function selectAnchor(element) {
    document.getElementById(element).className = ‘changeDiv’;
    }

    这样写的话可以有效地减少回流的次数,给浏览器减压。

  • 相关阅读:
    LeetCode:Container With Most Water
    c#编写的基于Socket的异步通信系统
    关于Thread类中三个interrupt方法的研究与学习(转)
    使用svnkit 的相关实例及相关问题汇总
    创业早期,联合创始人如何避免窝里反?(转)
    程序员解决问题的60个策略(转)
    码农和程序员之间的5个关键差异(转)
    LayoutInflater的使用
    2014年中国95家企业入围世界500强,超日本
    How to get the source code of the chromium of the specified revision
  • 原文地址:https://www.cnblogs.com/xuelixiang/p/4810160.html
Copyright © 2011-2022 走看看