有關css重繪和迴流的一個例子

最近作了一個導航條動畫,鼠標hover的時候會有一個可移動的下劃線,html結構大體以下css

<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樣式:html

.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的位置。web

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底下添加:ide

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

然而此處出現了問題,這麼作了頁面效果並無變化。
按理說修改left會致使頁面的重繪和迴流,可是實際上卻沒有達到預想的效果。函數

翻閱一些資料後,我的得出的結論是,瀏覽器爲了減小重繪的次數,會維護一個flush隊列,當有須要重排的時候將操做放入隊列,隊列滿時再一次性重繪。因此上面這兩句被瀏覽器合併到一塊兒寫入了。動畫

鑑於這個緣由,我嘗試出了兩種解決辦法:spa

  1. 使用setTimeoutcode

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

    這個方法已開始寫的時候只是嘗試性的,可是達到了須要的效果,具體緣由到底是由於瀏覽器任務插入的問題仍是由於執行其中函數前flush隊列已滿觸發了重繪,還真正沒有搞清楚。htm

  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');

    就能達到預想的效果了。

相關文章
相關標籤/搜索