那些年讓咱們頭疼的CSS3動畫

這是筆者整理的我的在CSS3動畫上遇到的問題,所有都是筆者我的的經驗,以及解決方案,並不相信網上會有重複的文章。你們能夠點進每一個小欄目的codeplay去地直觀feel一下。css

常見錯誤:Animation篇

首先先來複習一下animation的有哪些屬性:緩存

屬性名 默認 做用
animation-name none keyframe 的名字
animation-duration 0s 運行總時長
animation-timing-function ease 運行的速度變化,總不可能老是勻速吧
animation-delay 0s 延遲時間
animation-iteration-count 1 重複的次數,也能夠是無限的infinite
animation-direction normal 動畫執行方向,能夠正着來,也能夠反着來reverse
animation-fill-mode none important 動畫結束以後和開始以前的狀態,是否是動畫未開始的時候就是默認樣式,結束的時候又返回默認樣式。
animation-play-state running 動畫的狀態,注意若是說這個時候動畫運行結束了,狀態也是running,由於這個running不是表示動畫正在運行,而是一種狀態,有沒有被強行暫停。

常見錯誤一:動畫作完就disappear了!喂喂喂!沒讓你消失啊。code play~

這個應該是animation中的基礎題,因此放在了第一位。這個問題的解決方案就是animation-fill-mode這個屬性沒有設置或者設置錯誤。這個屬性從專業的角度來講是動畫的一個延續,就是0~100%的keyframe走完以後和開始以前的歸宿。簡單地來講就是動畫結束以後或者開始以前,當前元素的狀態是否保留動畫最後一幀的狀態或者未開始以前使用第一幀的樣式。這個屬性默認是不保留狀態,也就是說開始以前是原始狀態,開始以後纔開始轉換樣式,結束以後會馬上切換至原始狀態,彷彿這個動畫未曾存在過。這裏的forwards是指動畫結束以後(不管是正着來仍是倒這來)的狀態,backwards是指動畫delay的時候的狀態。both就很簡單了,包含告終束以後和開始以前的狀態。固然你們更喜歡both,這樣就不用考慮以前或者以後的問題了。bash

常見錯誤二:怎麼停不下來,想控制動畫的動態。code play~

這裏咱們能夠借用animation-play-state來控制動畫的是否繼續。劃重點,這邊的是否繼續並不包含從新開始。app

那麼,我可不能夠經過控制animation-direction的值來控制動畫的從新開始呢?好比我一個動畫reverse一下以後又從新開始了。emmm,想法很好,可是現實很殘酷。animation的time很智能,好比我在動畫的途中改變了動畫,而後animation會根據當前時間的反方向的狀態獲取狀態,而後從哪一個點開始執行,也就是說在動畫途中改變direction,最終動畫仍是按照原來的時間執行,也就是除非取消動畫,不然動畫的時間是固定的(固然會有一些小偏差)。因此想利用direction來讓動畫動起來就是太天真了。ide

既然如此,我可不能夠來回動呢,好比一個element,我但願他能夠從左到右再從右到左。這個時候animation-direction能夠設置爲alternate,這樣就會控制奇偶次數的不一樣動畫範圍,but!動畫次數要>1,否則哪裏來的奇偶呀~函數

這裏有一篇CSS triks上詳細講解如何從新開始動畫的博客,Restart CSS Animationoop

常見錯誤:Transition篇

複習一下transition的各個屬性值。佈局

transition屬性 默認值 做用
transition-delay 0 延遲
transition-duration 0 變換速度
transition-property all 變化屬性,默認監控所有變化,若是隻須要某一個值好比transform,就只監聽transform便可。
transition-timing-function ease 時間函數

只有我一我的以爲Transition是一個大坑嗎,感受比animation更難以駕馭。學習

常見錯誤三:是我眼花了嗎,怎麼直接結束了,彷彿未曾存在過。play code

有一種狀況,我在頁面首次渲染地時候就對transform進行了修改,想着只要改變tranform,transition就會工做。可是這個transition地工做性質是對比當前渲染狀態和上一次渲染狀態的的差異。所以像這個樣子改變,在首次渲染以前就改變了transform,transition失去了對比的參照物,而後就不動了,解決這個問題能夠用requestAnimationFrame解決,這個方法就是用於渲染前的最後一步也就是paint以前的一步,而後修改了layout,最後transition感覺到了召喚,識別出了差異,就正常工做了起來。動畫

FailTransition.style.transform="translateX(100px)"
requestAnimationFrame(()=>{
  SuccessTransition.style.transform="translateX(100px)"
})
複製代碼

步驟大概是這樣的:

Recalculate Style>Layout>requestAnimationFrame>Recalculate Style>Layout>Update Layer Tree>Paint>Composite Layers

還有一種狀況,就是咱們但願這個元素能夠先向右再向左,根據上次的經驗咱們能夠這麼寫,可是失效了,爲何呢?由於點擊以後設置的樣式,還沒抵達paint就被requestAnimationFrame重寫了,而後就按照最後一次的樣式和上一次渲染的樣式作了對比,進行了變換。

change.addEventListener("click",()=>{
    ChangeFrequency.style.transform="translateX(10000px)"
    requestAnimationFrame(()=>{
        ChangeFrequency.style.transform="translateX(50px)"
    })
})
複製代碼

爲了解決這個問題咱們能夠雙重requestAnimationFrame。然而能夠看到生效了,可是transition會自動修復,1s內完成的動畫,毫不會超時,所以咱們的動畫悲劇沒有按照咱們設定的那樣向右移動1s以後再向左執行1s,而是總時間1s,因此會閃現結束。

change.addEventListener("click",()=>{
    ChangeFrequency.style.transform="translateX(10000px)"
    requestAnimationFrame(()=>{
        requestAnimationFrame(()=>{
            ChangeFrequency.style.transform="translateX(50px)"
        })
    })
})
複製代碼

至於如何實現串聯動畫,個人第一選擇是animation,第二選擇是監聽transitionend事件,當地一個動畫結束後再執行以後的動畫。

function moveBack(){
  ChangeFrequencyFix.style.transform="translateX(50px)"
  ChangeFrequencyFix.removeEventListener("transitionend",moveBack)
}
ChangeFrequencyFix.addEventListener("transitionend",moveBack)

複製代碼

常見錯誤四:怎麼回事!怎麼從奇怪的地方出現了!這是一個小bug。code play

理想是從左上到右下,而後放大,動畫結束後,從新從原點出發,從上放大滑動到下方,而後卻直接從右下平行滑動到了最後的位置,這個小bug能夠說是做死。由於transition的特性是保留上一次動畫的最後一幀,而後過渡到新的狀態,若是不想要某一個狀態的重置,記得關閉transition,不然就會出現連續的動畫。

function goTrravel(){
  correctToGo.removeEventListener("transitionend",goTrravel)
  correctToGo.style.transition="none"
  correctToGo.classList.remove("active")
  requestAnimationFrame(()=>{ 
    requestAnimationFrame(()=>{ 
      correctToGo.classList.add("pop")
      correctToGo.style.transition="transform 2s,opacity 2s"
    })
  })
}
correctToGo.addEventListener("transitionend",goTrravel)
複製代碼

由於transition是實時監控的,因此若是若是去除了transform的狀態,他會回到default的狀態。所以,若是想要拋棄回到初始化或者某一狀態須要重置transition。

常見錯誤五:喂喂喂,你怎麼還在這個層下面,我都給你z-index:1000了,你快出來啊。動畫提高層code play

這裏須要提出兩個概念一個是css context stack,MDN參考網址

通常狀況下若是想要層級高,就用z-index設置就能夠了。甚至父節點A的層級低於父節點B的層級,可是,再沒有提高層的狀況下,同一層中父節點A的子節點能夠高於父節點B的層級。可是如果產生了提高層,除非整個父節點A高於父節點B,父節點A中的子節點才能夠高於父節點B的層級。

下圖就是一個例子,你們能夠看見下面這個產生提高層的狀況,裏面的黃色子節點是沒法突破紅色節點的,由於他們已經處於不一樣的層了。z-index只做用於當前層,沒有跨層處理的能力。

常見錯誤六:will-change和translateZ(0)做用是同樣的。

這一塊,咱們都知道若是想要加速GPU渲染就使用相似於hack的translateZ(0)或者是CSS新屬性will-change,那麼這二者的原理是什麼,具體的使用狀況是什麼?

其實他們就是一個提高層的概念,將以後可能會改變的元素從當前的層中抽離,阻止composition,這樣這部分修改的時候就不會影響整個頁面的佈局,從而阻止了reflow。

那麼translateZ(0)的做用是否和will-change同樣呢?不!

雖然他們都是提高層,可是will-change帶有緩存做用,也就是說change的內容會被緩存,只有第一動畫回paint以後的重複動畫就不會再繪製,可是translateZ(0)每次動畫都會從新繪製。能夠說will-change對於重複動畫頗有好了。可是!不要濫用哦~will-change會緩存,所以很佔內存。你們慎用。

參考連接:

  • youtu.be/cCOL7MC4Pl0 , JS conf上面講evenloop的視頻,裏面的evenloop和渲染的關係對筆者的啓發很大。
  • developer.mozilla.org/zh-CN/docs/… , MDN是研究CSS必備網站。
  • www.w3.org/TR/2016/WD-… , 若是想要深刻研究layer這一塊,能夠參考CSS的規範,能夠又更深刻的感覺。不過CSS的規範是給你們深刻學習CSS的,並非教你們如何使用的。

注:

原創聲明!所有都是筆者一個字一個字敲出來,代碼是筆者一個個code出來的。

歡迎轉載,註明出處。

相關文章
相關標籤/搜索