animation-fill-mode的一些思考

来源:http://www.cnblogs.com/lyzg/archive/2016/08/08/5738860.html
-Advertisement-
Play Games

animation-fill-mode是css3動畫的一個屬性,它能夠控制元素在動畫執行前與動畫完成後的樣式。一個帶有延遲,並且按正常方向執行的動畫(正常方向是指從0%運行到100%),執行一次的過程可以描述如下: 按照動畫的執行時間來劃分,一次動畫過程可以將元素劃分為3個狀態:動畫等待,動畫進行和... ...


animation-fill-mode是css3動畫的一個屬性,它能夠控制元素在動畫執行前與動畫完成後的樣式。一個帶有延遲,並且按正常方向執行的動畫(正常方向是指從0%運行到100%),執行一次的過程可以描述如下:

image

按照動畫的執行時間來劃分,一次動畫過程可以將元素劃分為3個狀態:動畫等待,動畫進行和動畫結束狀態。預設情況下,只有在動畫進行狀態,才會應用動畫的keyframes所定義的樣式;而在動畫等待和動畫結束狀態,不會對元素的樣式產生影響。animation-fill-mode有四個值,分別是:

none:這是預設值,正是這個值,使得動畫不會對動畫等待和動畫完成的元素樣式產生改變;

backwards:如果設置為這個值,那麼在動畫等待的那段時間內,元素的樣式將設置為動畫第一幀的樣式;

forwards:如果設置為這個值,那麼在動畫結束後,元素的樣式將設置為動畫的最後一幀的樣式;

both:相當於同時配置了backwards和forwards,意味著在動畫等待和動畫結束狀態,元素將分別應用動畫第一幀和最後一幀的樣式。

通過下麵的demo,可以感受下animation-fill-mode三個非none值的作用。

demo1:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo1

效果如下:

demo1

less源碼:

#demo1 {
  .target.animate {
    animation-name: move_1;
    animation-duration: 2s;
    animation-delay: 1s;

    &.target_1 {
      animation-fill-mode: backwards;
    }
    &.target_2 {
      animation-fill-mode: forwards;
    }
    &.target_3 {
      animation-fill-mode: both;
    }
  }
}

@keyframes move_1 {
  0% {
    transform: translate(-50px, 0);
  }

  50% {
    transform: translate(0, 0);
  }

  100% {
    transform: translate(50px, 0);
  }
}

在以上demo中,定義了一個move_1的動畫,它包含三個關鍵幀,第一幀讓元素往左偏移50px,最後一幀讓元素往右偏移50px,這個偏移都是相對元素的初始狀態而言的(就是沒有添加動畫的狀態)。demo中從上到下有三個元素,分別應用了animation-fill-mode屬性的三個值:backwards,forwards,both。結合前面對這三個屬性值的說明,相信不難理解demo中三個元素的動畫效果:

backwards和both使得第一個元素和第三個元素,在動畫添加後都立即變為動畫第一幀的狀態。而第二個元素沒有應用第一幀的狀態。

forwards和both使得第二個元素和第三個元素,在動畫結束後仍然保持動畫最後一幀的狀態。而第1個元素沒有。

以上內容可能會讓人覺得animation-fill-mode是一個比較簡單的屬性,因為它的作用非常的簡單明瞭。儘管如此,我在最近做一些動畫效果的時候卻發現,這個屬性在真正使用的時候要想完全融會貫通地去使用,還真不是那麼容易,尤其是當我們需要同時應用多個動畫,定義連續的複雜動畫時,就可能會在寫動畫的過程中,碰到一些自己按理論不能理解清楚的點,雖然最後吧,我們總是能想辦法搞定我們遇到的問題,那是因為這個屬性畢竟只有那麼幾個值,多加調試當然能解決問題,但是做完了,心裡面還是想解決那個為什麼我之前那麼寫就不行的問題。所以本文從一些非常規的角度來研究animation-fill-mode在實際使用過程中可能會存在理解偏差的問題,我不敢保證在本文中,我提出的一些理解方式一定是正確的,只是以我現在的經驗,只能得出這麼些結論。希望本文可以拋磚引玉,發現一些更可靠更完美的思想。

首先,我想對animation-fill-mode的理論知識再做一次補充說明:

1)在animation-fill-mode的基礎知識中,有這麼幾個關鍵詞:動畫等待時間(也叫動畫延遲時間),動畫結束後,第一幀,最後一幀。這些關鍵詞的更深的含義是:

a. backwards一定是在動畫延遲時間內才會生效;

b. forwards一定在動畫完成之後才會生效,對於一個迴圈的動畫來說,它沒有動畫完成後的狀態,所以forwards不會起作用;

c. 第一幀和最後一幀不是絕對的,就是說第一幀不一定永遠跟0%這幀對應,最後一幀不一定永遠跟100%這幀對應。具體到底0%是第一幀還是100%是第一幀,跟另外兩個動畫屬性有關係:animation-direction和 animation-iteration-count。舉個例子:當animation-direction是alternate,animation-iteration-count是2的時候,第一幀和最後一幀就都是0%。至於為啥是這樣,自己簡單畫個圖就好理解了:

image

詳細的規則在mdn上有完整地說明,所以這裡不會再贅述了。這個規則並不存在理解偏差的問題,但是對於animation-fill-mode的第一幀跟最後一幀該如何判別還是比較重要的,所以有必要記錄一下。

為了不增加以下內容的複雜性,剩下的內容都將以animation-direction為normal,animation-iteration-count為1這個前提來說明。接下來就來看看animation-fill-mode這個屬性,還有哪些問題值得花點心思研究研究的。

1. 動畫沒有定義0%或100%的時候

假如我們動畫里沒有定義0%或100%,只定義了中間百分比的關鍵幀,animation-fill-mode會有什麼樣的表現呢?

先來觀察demo2:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo2

demo2

less源碼:

#demo2 {
  .target.animate {
    animation-name: move_2;
    animation-duration: 2s;
    animation-delay: 1s;

    &.target_1 {
      animation-fill-mode: backwards;
    }
    &.target_2 {
      animation-fill-mode: forwards;
    }
    &.target_3 {
      animation-fill-mode: both;
    }
  }
}

@keyframes move_2 {
  50% {
    transform: scale(1.2, 1.2);
  }
}

在這個demo中,你會看到三個元素應用了不同的animation-fill-mode,最終的效果卻完全相同。這是因為動畫裡面沒有定義0%,和100%,導致animation-fill-mode找不到它所需要的第一幀和最後一幀。儘管上面的demo動畫中,50%在動畫定義裡面,它是唯一的一幀,按照我們對唯一性的認識,那麼50%這幀既可以看作是一幀,也可以看作是最後一幀,但是animation-fill-mode只認動畫定義里的0%和100%,而不是動畫定義里的第一幀和最後一幀

那麼是不是意味著沒有0%和100%的話,animation-fill-mode就一定沒有作用呢?

其實不是。當動畫定義裡面沒有0%和100%的時候,並不是意味著動畫就沒有起始幀跟結束幀了,任何一個動畫一定具有起始幀和結束幀,預設情況下起始幀跟結束幀所對應的樣式就是元素未添加的動畫前的樣式,我們可以通過0%或100%,來覆蓋預設的起始幀和結束幀的定義。也就是說,當沒有0%或100%的時候,animation-fill-mode還是起作用的,只不過它是用元素的初始狀態來起作用,所以你看不出來而已。

上一段的結論,我並沒有在w3c上看到有介紹,而是我根據自己的一些思考跟觀察猜測出來的。接下來我會用chrome的動畫調試工具來輔助說明我的判斷,在後面介紹animation-fill-mode在多個動畫中的實踐時,我還會結合一個例子並用這些理論來解釋。

新版的chrome提供了動畫調試的功能,打開方式如下:

image

出現Animations這個選項卡之後,就會看到類似下麵的一個控制台,在這裡我們能夠通過控制時間軸的方式調試動畫:

image

當打開Animations控制台後,它會在頁面載入完後就監聽頁面里的動畫效果,比如當我們點擊demo2的添加動畫按鈕,控制台就能看到demo2裡面發生的動畫:

demo2_2

 

這個動畫控制台,可以實現調整動畫的時間軸,動畫暫停,動畫速度控制以及逐幀觀察等較強的動畫管理功能,但是本文不會深入介紹它的使用了,感興趣的可以在自己的工作中去多多使用。現在我想要這個動畫控制台的呈現來說明前面我所提出的結論,我前面的結論是:任何動畫不管有沒有定義0%和100%,一定具有起始幀和結束幀,只不過我們可以用0%和100%來覆蓋。

回到本文的demo1,我把頁面刷新,然後點擊demo1裡面的添加動畫按鈕,然後來觀察動畫控制台,它呈現的內容是:

image

由於demo1的動畫裡面,一共包含了三個關鍵幀定義,所以在動畫控制台,我們能看到每個元素的動畫時間軸上都包含了三個點,其中第一個點和最後一個點都是實心的,代表它們是動畫的起始幀和結束幀;然後中間的點是空心的,代表它是動畫執行過程中的關鍵幀。

再來看demo2,我以同樣的方式添加動畫,再來觀察控制台:

image

對比demo1的截圖,可以發現,儘管demo2中的動畫只定義了1個50%的關鍵幀,但是在動畫的時間軸上,依然出現了代表起始幀和結束幀的點,這也從一方面說明瞭,動畫不管有沒有0%和100%,起始幀和結束幀是一定存在的。

前面這個小結論,對於後面更複雜的一個實例的理解,比較關鍵,也是基於它,我才能得出後面更大的一個關於動畫過程中屬性衝突時優先順序的猜想,所以這裡花了不少的內容來介紹它。

接下來繼續後面要探究的問題。

2. 動畫作用過程中的樣式與元素初始狀態的樣式衝突

在這個問題標題中,我用到了“動畫作用過程”這個短語,而不是“動畫過程”,是因為這兩個的含義是不一樣的。按照文首對動畫階段的劃分,一個元素添加一個動畫後,它就會經歷三個階段:動畫等待,動畫執行和動畫結束。我們知道動畫要做的事情,就是把動畫定義裡面的樣式應用到元素上,而且我們可以確定的是動畫執行階段,動畫定義的樣式是一定會作用到元素之上的。那麼在動畫等待以及動畫結束階段呢,動畫定義的樣式是否也會作用到元素之上?這個就跟animation-fill-mode有關係了,如果該屬性取forwards,那麼動畫結束階段會受到動畫結束幀定義的樣式的作用;如果該屬性取backwards,那麼動畫等待階段,也會受到動畫起始幀的作用;如果取both,那麼動畫結束跟動畫等待階段都會影響。換句話說:

如果animation-fill-mode取none,動畫對一個的作用過程,簡稱之動畫作用過程,就僅僅包括了動畫執行階段;

如果animation-fill-mode取backwards,動畫作用過程就包含動畫等待階段跟動畫執行階段;

如果animation-fill-mode取forwards,動畫作用過程就包含動畫執行階段跟動畫結束階段;

如果animation-fill-mode取both,動畫作用過程就是整個添加動畫之後的過程了。

以上提到的這個結論是對單個動畫而言的,如果一個元素應有了多個動畫,那麼每個動畫都會滿足這個結論。

我們可以從動畫控制台來直觀感受下動畫作用過程的不同類型。

這個結論,我也做了一個demo:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo3

demo3

less源碼:

#demo3 {
  .target.animate {
    animation-name: move_3;
    animation-duration: 2s;
    animation-delay: 1s;

    &.target_1 {
      animation-fill-mode: none;
    }
    &.target_2 {
      animation-fill-mode: backwards;
    }
    &.target_3 {
      animation-fill-mode: forwards;
    }
    &.target_4 {
      animation-fill-mode: both;
    }
  }
}

@keyframes move_3 {
  50% {
    transform: scale(1.2, 1.2);
  }
}

不過這一塊的目的不是為了說明這個demo的動畫效果,而是為了介紹如何從動畫控制台去看動畫作用過程的範圍:

image

從源碼中可以看到:

.target_1應用了animation-fill-mode:none

.target_2應用了animation-fill-mode:backwards

.target_3應用了animation-fill-mode:forwards

.target_4應用了animation-fill-mode:none。

結合這個可以看出,動畫控制臺中,時間軸實心的部分就是動畫的作用過程

接下來回到本部分要研究問題主題,就是當元素在動畫作用過程中的時候,動畫定義的屬性與元素初始的屬性衝突時會有什麼表現。

先看這個demo:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo4

image

(動畫內容較多,所以沒做gif,可以去上面的鏈接中查看)

less源碼:

#demo4 {
  .target {
    transform: scale(1.2, 1.2);
  }

  .target.animate {
    animation-duration: 2s;
    animation-delay: 1s;

    &.target_1 {
      animation-fill-mode: none;
      animation-name: move_4_01;
    }
    &.target_2 {
      animation-fill-mode: backwards;
      animation-name: move_4_01;
    }
    &.target_3 {
      animation-fill-mode: forwards;
      animation-name: move_4_01;
    }

    &.target_1_02 {
      animation-fill-mode: none;
      animation-name: move_4_02;
    }
    &.target_2_02 {
      animation-fill-mode: backwards;
      animation-name: move_4_02;
    }
    &.target_3_02 {
      animation-fill-mode: forwards;
      animation-name: move_4_02;
    }
  }
}

@keyframes move_4_01 {
  0% {
    transform: translate(-50px, 0);
  }

  50% {
    transform: translate(0, 0);
  }

  100% {
    transform: translate(50px, 0);
  }
}

@keyframes move_4_02 {
  0% {
    transform: translate(-50px, 0) scale(1.2, 1.2);
  }

  50% {
    transform: translate(0, 0) scale(1.2, 1.2);
  }

  100% {
    transform: translate(50px, 0) scale(1.2, 1.2);
  }
}

在上面的截圖中,我用箭頭把元素跟動畫控制臺中的動畫元素時間軸做了一個對應關係,方便理解。

在這個demo裡面,元素預設都有一個transform: scale(1.2,1.2)的設置,然後定義兩個動畫,move_4_01這個動畫的樣式定義裡面同樣包含了一個transform屬性,而且沒有保留元素預設的transform設置。move_4_02這個動畫的樣式定義裡面也包含了一個transform的設置,跟move_4_01不同的是,這個動畫還保留了元素預設的scale(1.2,1.2)的設置。

demo中用到了六個元素,它們按照animation-fill-mode分成了三組,以便對應不同的動畫作用過程;每組裡面的兩個元素,分別應用move_4_01和move_4_02兩個動畫。

通過在時間軸上的動畫等待階段,動畫執行階段和動畫結束階段,任取三個時間點,觀察元素的表現,可以幫助分析在動畫作用過程中,當動畫屬性與初始屬性衝突時存在的規律:

動畫等待階段:

image

動畫執行階段:

image

動畫結束階段:

image

考慮到篇幅的原因,這裡就不再詳細的分析以上各個截圖的現象了。我最終得出的結論是:在動畫屬性與初始屬性衝突的時候,只要一個元素處於動畫作用過程中,就會啟用動畫定義的屬性,覆蓋元素初始化的屬性。而前面的結論告訴我們,animation-fill-mode可以改變元素的動畫作用過程,所以明白這點,對於做動畫的狀態分析會比較有幫助。

繼續下一個問題。

3. 一個元素應用多個動畫時,多個動畫定義的屬性衝突

當一個元素應用了多個動畫時,假如動畫定義的屬性有衝突,也就是說多個動畫都用到了同一個屬性,這種衝突該怎麼去分析呢?

先來看下一個demo5:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo5

demo5

less源碼:

#demo5 {
  .target.animate {
    animation-duration: 1s, 1s;
    animation-delay: 1s, 2s;
    animation-fill-mode: both;

    &.target_1 {
      animation-name: move_5, bg_change_5;
    }
    &.target_2 {
      animation-name: bg_change_5, move_5;
    }
  }
}

@keyframes move_5 {
  0% {
    transform: translate(-50px, 0);
  }

  50% {
    transform: translate(0, 0);
  }

  100% {
    transform: translate(50px, 0);
  }
}

@keyframes bg_change_5 {
  0% {
    background-color: orange;
    transform: scale(0.8);
  }

  100% {
    background-color: red;
    transform: scale(1.2);
  }
}

在這個demo里,定義了2個動畫,move_5變元素在x軸的偏移,bg_change_5同時改變元素的縮放和背景色。兩個元素都同時應用了這兩個動畫,除了應用時的順序不同,其它的參數如延遲,持續時間,animation-fill-mode都完全相同。結合動畫控制台顯示的時間軸,我們來看看這兩個元素在動畫作用過程中都有什麼規律。

以動畫等待階段為例:

image

這個階段,兩個元素都呈現了橙色背景,.target_1除了有橙色背景,同時大小比預設的尺寸明顯有縮小;.target_2除了有橙色背景外,大小沒有變化,但是往左偏移了一點。從以上源碼可知,影響背景色和尺寸的動畫肯定是bg_change_5,影響元素在x軸偏移的肯定是move_5。雖然兩個元素都同時應用了兩個動畫,並且延遲,持續以及animation-fill-mode都相同,但是表現的狀態卻不完全一致。它們唯一的不同在於應用動畫的順序,.target_1的動畫順序為:move_5,bg_change_5。.target_2的動畫順序為bg_change_5,move_5。所以這個現象最終的合理解釋就是:

.target_1因為bg_change_5動畫在後,所以bg_change_5裡面第一幀的transform: scale(0.8)覆蓋了move_5裡面第一幀的transform: translate(-50px,0);

.target_2因為move_5在後,所以move_5裡面的transform: translate(-50px,0)覆蓋了transform: scale(0.8)

也就是說,當多個動畫的屬性衝突的時候,後應用的動畫的優先順序高於先應用的動畫優先順序。但要註意的是這個結論是不嚴謹的,為什麼?

因為這個結論的是基於250ms這個時刻來說的,對於一個可能應用了多個動畫的元素來說,時刻點不同,意味著每個動畫都有可能處於不同的動畫階段,有的可能還在等待階段,有的可能在執行階段,有的已經是完成階段了,比如:

image

image

要證明前面的結論是否成立,需要在時間軸上多取一些時刻來驗證才行。不過最後還是考慮到篇幅的原因,我也沒辦法找更多的時刻點截圖來分析了,直接出結論吧,就是前面說的在我的幾種測試下,都是客觀成立的結論。

只是前面的結論描述還不夠簡單明瞭,下麵我會給出一個更加直白的說明。先來看看這張圖:

image

這張圖描述的就是一個元素,同時應用多個動畫之後,在動畫控制台看到各個動畫的時間軸。從圖中我們可以得出以下信息:

動畫的應用順序為:animate_1 , animate_2 , animate_3

animate_1的延遲時間為t4(距t4還有1/5的位置)-t1,動畫結束時刻為t8

animate_2的延遲時間為0,動畫結束時刻為t5

animate_3的延遲時間為t3-t1,動畫結束時刻為t7

我們假設在這個圖中,所有動畫的animation-fill-mode都設置為both,意味著圖中所有的時間軸的實心部分就表示為動畫的作用過程,那麼在時間軸上任取一個時刻,如果多個動畫在這一時刻有屬性衝突,那麼屬性的優先順序就完全由動畫的應用順序決定,後應用的動畫優先順序高:

image

有了這個結論,將來在分析一些多動畫效果的時候就會比較好下手了。我們只要先確定好單個動畫的作用過程,然後找到我們需要分析的動畫時間軸的點,最後再從上往下找到最後一個包含衝突屬性的動畫軸即可。

另外,從這部分的問題,我還想說明另外一個結論,這個結論比較好理解,也沒太多要去分析的,就是應用多動畫的時候,各個動畫之間都是獨立的,所以動畫的那些屬性,如animation-delay, animation-fill-mode不會受其它動畫的影響。這個從動畫控制台各個動畫獨立的時間軸也能看出來。為什麼會有這個結論呢,是因為在我沒有去研究到這些規律之前,我以為動畫的animation-fill-mode可能會受多個動畫的animation-delay的影響,就拿前面的demo來說,元素在應用動畫時,第一個動畫延遲1s,第二個動畫延遲2s,我初以為第二個動畫的animation-fill-mode會在第一個動畫的延遲結束之後才會生效,不然這兩個動畫如果同時應用animation-fill-mode的話,屬性衝突該怎麼解決?最後有了前面兩個重要的結論,我原來的那個認識也就很好解釋了。

接下來看一個簡單實際的多動畫的例子,來看看多動畫的效果如果碰到問題該怎麼分析。

4. 實例分析

這個演示的效果實例是,元素預設是隱藏的,當添加動畫後,元素以淡入的方式從x軸向左偏移-50px的位置,移動到原位置,顯示1s之後,再從原位置以淡出的方式,移動到x軸往右偏移50px的位置。正確的效果如下:

demo6

一開始我的做法是這樣的:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo6

#demo6 {
  .target:not(.target_1) {
    visibility: hidden;
    opacity: 0;
  }

  .target.animate {
    &.target_2 {
      animation-name: move_6_01, move_6_02;
      animation-duration: 1s, 1s;
      animation-delay: 0s, 2s;
      animation-fill-mode: both;
    }
  }
}

@keyframes move_6_01 {
  0% {
    visibility: hidden;
    opacity: 0;
    transform: translate(-50px, 0);
  }

  100% {
    visibility: visible;
    opacity: 1;
    transform: translate(0, 0);
  }
}

@keyframes move_6_02 {
  100% {
    visibility: hidden;
    opacity: 0;
    transform: translate(50px, 0);
  }
}

正如你所看到的,我定義了兩個動畫move_6_01,move_6_02,這兩個動畫按照01 02 的順序應用到.target_2這個元素上,兩個動畫持續時間都是1s,第一個動畫延遲時間為0,第二個動畫延遲時間為2s,以便達到淡入淡出的時間都為1s,然後中間停留的時間也是1s的效果;兩個動畫同時應用了animation-fill-mode:both。然後還給.target_2這個元素設置了初始的屬性:visibility: hidden,opactity: 0。.target_1只是一個對比的元素,沒有添加動畫效果。

當我運行這個代碼的時候最後卻發現,一點動畫效果都沒有,動畫控制台已經監聽到動畫了,但是元素看不見動畫效果:

image

我以為是animation-fill-mode的原因,所以我在上面的demo基礎上,將animation-fill-mode稍加調整,改為both,forwards,也就是第二個動畫不啟用backwards的效果:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo7

這個時候效果變成:

demo7

代碼:

#demo7 {
  .target:not(.target_1) {
    visibility: hidden;
    opacity: 0;
  }

  .target.animate {
    &.target_2 {
      animation-name: move_6_01, move_6_02;
      animation-duration: 1s, 1s;
      animation-delay: 0s, 2s;
      animation-fill-mode: both,forwards;
    }
  }
}

在這一步,淡入跟停留的效果出來了,可是淡出的效果沒有出來。

雖然最後,我在不明白這其中的原理的前提下,將動畫調試出來了,但是對於這個問題還是覺得很有必要去深入研究一下,這也是我寫本文的初衷。有了之前的那些結論,接下來就看看如何分析前面兩步的現象產生的原因。

先來看看demo6(就是本部分的第一個)的動畫時間軸:

image

前面說過,動畫是獨立的,動畫時間軸的實心部分表示動畫作用過程,多動畫的時候,在動畫控制臺中,可以根據從上往下的順序判斷屬性的優先順序。觀察上面的截圖發現:在動畫添加後,兩個動畫的作用過程都是相同的,而由於move_6_02這個動畫後應用,所以move_6_02這個動畫,在有屬性衝突的時候,優先順序始終是高的那一個。

那麼為什麼在添加動畫後,什麼動畫效果都看不到呢?這個原因在於move_6_02這個動畫只定義了100%這一幀,沒有定義0%,那就意味著move_6_02這個動畫的起始幀會用元素預設的屬性定義來代替。而元素的預設屬性中有兩個屬性會導致元素在動畫過程的0-2s都不會顯示,就是visibility: hidden,opactity: 0這兩個屬性。

我一開始的理解是,move_6_01這個動畫的100%這一幀,會讓元素顯示出來(visibility: visible,opactity: 1),所以move_6_02只用定義100%這一幀即可。但是動畫是獨立的,move_6_02這個動畫的作用不會跟其它動畫有關聯,所以以上做法無法實現需要的效果。

再來看demo7:

image

在demo7裡面,animation-fill-mode調整為both,forwards,改變了兩個動畫的作用過程,解決了move_6_02優先順序高導致move_6_01的效果看不進的問題,但是為什麼demo7在2s之後沒有出現淡出的效果呢?

這個還是跟move_6_02這個動畫沒有定義0%這一幀有關係。當動畫沒有定義0%的時候,就會用預設的屬性來作為起始幀。而元素的預設屬性是

visibility: hidden,opactity: 0,move_6_02的100%裡面定義的屬性也是visibility: hidden,opactity: 0,也就是說這個動畫實際上不會對元素的可見性做任何的改變,其實偏移還是有的,只是看不見而已。

所以最好解決這個問題,只要在demo7的基礎上,給move_6_02加一個0%的定義即可:

http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo8

#demo8 {
  .target:not(.target_1) {
    visibility: hidden;
    opacity: 0;
  }

  .target.animate {
    &.target_2 {
      animation-name: move_8_01, move_8_02;
      animation-duration: 1s, 1s;
      animation-delay: 0s, 2s;
      animation-fill-mode: both,forwards;
    }
  }
}

@keyframes move_8_01 {
  0% {
    visibility: hidden;
    opacity: 0;
    transform: translate(-50px, 0);
  }

  100% {
    visibility: visible;
    opacity: 1;
    transform: translate(0, 0);
  }
}

@keyframes move_8_02 {
  0% {
    visibility: visible;
    opacity: 1;
    transform: translate(0, 0);
  }

  100% {
    visibility: hidden;
    opacity: 0;
    transform: translate(50px, 0);
  }
}

通過這個例子,希望能讓大家明白本文總結的一些理論的實踐方法。

總結

其它的就不多說了,把本文提出的一些結論稍微提煉一下,希望這些東西對大家今後做複雜的動畫效果有所幫助:

1. 動畫是獨立,各自都有各自的時間軸,互不影響。

2. animation-fill-mode只認動畫定義里的0%和100%,而不是動畫定義里的第一幀和最後一幀。

3. 當動畫定義裡面沒有0%和100%的時候,並不是意味著動畫就沒有起始幀跟結束幀了,任何一個動畫一定具有起始幀和結束幀,預設情況下起始幀跟結束幀所對應的樣式就是元素未添加的動畫前的樣式,我們可以通過0%或100%,來覆蓋預設的起始幀和結束幀的定義。

4. 動畫控制臺中,時間軸實心的部分就是動畫的作用過程。在動畫屬性與初始屬性衝突的時候,只要一個元素處於動畫作用過程中,動畫里定義的屬性優先順序始終高於元素的初始屬性。

5. 多動畫效果中,要判斷任意時刻,哪個動畫的優先順序高,只要在動畫控制臺中,找到該時刻對應的線,該線與所有動畫的實心部分(動畫作用過程)的交集,按照從上往下的順序,越往下的點的優先順序越高。

謝謝閱讀。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、概述 外觀模式提供了一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。 二、解決問題 在上一講中,我們學習了適配器模式,它是用來轉換一個介面的,而外觀模式可以理解為轉換一群介面,客戶只要調用一個介面,而不用調用多個介面就可以達到目的。想想現實生活中例子,我們 ...
  • 一、概述 適配器模式將一個類的介面,轉換為客戶期望的另一個介面。適配器讓原本不相容的類可以合作無間 二、解決問題 從模式的定義中,我們看到適配器模式就是用來轉換介面,解決不相容問題的。想想我們現實生活中的適配器,最常用的就是手機充電器了,也叫做電源適配器,它把家用交流強電轉換為手機用的直流弱電。其中 ...
  • 還記得剛學ADO.NET的情景麽?還記得當年是怎麼從ADO.NET被忽悠到用SqlHelper的麽?話說從入門到走上工作崗位那些年,我們就一直被純純地教導或引導,ADO.NET太原始,得封裝成SqlHelper或DBHelper......後來,這種思維一直深深就存在腦海裡,並不知不覺中進入了潛意識... ...
  • 線上預覽 源碼下載 lightgallery.js是一款純JavaScript輕量級響應式lightbox插件。該Lightbox插件支持圖片,視頻,iframe等多種媒體。支持全屏,導航,縮放,下載等功能,還支持多種動畫過渡效果。lightgallery.js的特點還有: 完全響應式設計。 內置插 ...
  • 記得一年前,到一家公司面試的時候,問我position有哪幾個屬性,我憋半天才回答出2個,大家估計都清楚,就是我們經常用到的2個(relative,absolute)。 最近又用到了好多,深入研究了下。 一、語法: position:static | relative | absolute | fi ...
  • html代碼: <div class="div"></div> css代碼: .div{ border-top:40px solid #ff0077; border-left:40px solid #004444; border-bottom:40px solid #999999; border-r ...
  • 安裝Gulp.js Gulp是給予Node.js的,故首先安裝Node.js[1],完成之後執行下麵的命令安裝Gulp: npm install -g gulp //-g (global)執行全局安裝gulp,這樣在任何地方都可以進行 gulp 操作 安裝完成之後,需要在我們的項目中使用,需要命令行 ...
  • var obj1={apple:0,banana:{weight:52,price:100},cherry:97}; $.exytend(obj1); $.cherry >97 $.apple >0 $.banana >{weight:52,price:100} var obj2={banana:{ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...