有关css重绘和回流的一个例子

近来做了一个导航条动画,鼠标hover的时刻会有一个可挪动的下划线,html构造大抵以下

<div class="nav-sliderbar fl rel">
    <ul class="clearfix">
        <li class=""><a href="/b/AAA">AAA</a></li>
        <li class=""><a href="/b/BBB">BBB</a></li>
        <li class=""><a href="/b/CCC">CCC</a></li>
        <li class=""><a href="/b/DDD">DDDD</a></li>
    </ul>
    <span class="slider-underline"></span>
</div>

slider-underline运用了transition款式:

.slider-underline {
    position: absolute;
    border-width: 1px 0;
    border-style: solid;
    border-color: #444;
    height: 0px;
    bottom: 12px;
    width: 26px;
    left : -26px;
    -webkit-transition: left 0.2s cubic-bezier(0.16, 0.71, 0.46, 1.43);
       -moz-transition: left 0.2s cubic-bezier(0.16, 0.71, 0.46, 1.43);
         -o-transition: left 0.2s cubic-bezier(0.16, 0.71, 0.46, 1.43);
            transition: left 0.2s cubic-bezier(0.16, 0.71, 0.46, 1.43);
}

在页面天生的时刻依据板块差别须要初始化slider-underline的位置。

var underline_width = $('.slider-underline').width();
var active_position = $('.nav-sliderbar .actived').length ? $('.nav-sliderbar .actived').width()/2 + $('.nav-sliderbar .actived').position().left - underline_width/2 : - underline_width;
//上面两句是盘算的导航条滑块的初始的位置,正好在激活的板块对应位置的下方。
$('.slider-underline').css('left', active_position+'px');

由于slider-underline默许有transition,因而在页面革新初始化其left位置的时刻就会触发动画结果。这个体验不是很好,愿望能在初始化的时刻不触发这个动画,因而斟酌了将动画结果做成一个类:

.underline-bezier {
    -webkit-transition: left 0.2s cubic-bezier(0.16, 0.71, 0.46, 1.43);
       -moz-transition: left 0.2s cubic-bezier(0.16, 0.71, 0.46, 1.43);
         -o-transition: left 0.2s cubic-bezier(0.16, 0.71, 0.46, 1.43);
            transition: left 0.2s cubic-bezier(0.16, 0.71, 0.46, 1.43);
}

js底下增加:

   $('.slider-underline').css('left', active_position+'px');
   $('.slider-underline').addClass('underline-bezier');

然则此处涌现了题目,这么做了页面结果并没有变化。
按理说修正left会致使页面的重绘和回流,然则实际上却没有到达料想的结果。

翻阅一些材料后,个人得出的结论是,浏览器为了削减重绘的次数,会保护一个flush行列,当有须要重排的时刻将操纵放入行列,行列满时再一次性重绘。所以上面这两句被浏览器合并到一同写入了。

鉴于这个缘由,我尝试出了两种解决办法:

  1. 运用setTimeout

    setTimeout(function() {
        $('.slider-underline').addClass('underline-bezier');
    },0);

    这个要领已最先写的时刻只是尝试性的,然则到达了须要的结果,详细缘由终究是由于浏览器使命插进去的题目照样由于实行个中函数前flush行列已满触发了重绘,还真正没有搞清楚。

  2. 强迫提早flush行列
    当猎取以下属性的时刻,浏览器为了猎取正确的位置会强迫浏览器提早flush行列。

    1. offsetTop, offsetLeft, offsetWidth, offsetHeight

    2. scrollTop/Left/Width/Height

    3. clientTop/Left/Width/Height

    4. width,height

    5. getComputedStyle() / currentStyle

    因而将js改成:

    $('.slider-underline').css('left', active_position+'px');
    var get_left = $('.slider-underline').css('left');
    $('.slider-underline').addClass('underline-bezier');

    就可以到达料想的结果了。

    原文作者:saigyouyou
    原文地址: https://segmentfault.com/a/1190000008915952
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞