動畫開發 --- css和javascript方式

Transition

CSS3 過渡是元素從一種樣式逐漸改變爲另外一種的效果git

描述
transition-property 指定CSS屬性的name,transition效果
transition-duration transition效果須要指定多少秒或毫秒才能完成
transition-timing-function 指定transition效果的轉速曲線
transition-delay 定義transition效果開始的時候

transition-property

描述
none 沒有屬性會得到過渡效果。
all 全部屬性都將得到過渡效果。
property 定義應用過渡效果的 CSS 屬性名稱列表,列表以逗號分隔。

transition-timing-function

描述
linear 規定以相同速度開始至結束的過渡效果(等於 cubic-bezier(0,0,1,1))。
ease 規定慢速開始,而後變快,而後慢速結束的過渡效果(cubic-bezier(0.25,0.1,0.25,1))。
ease-in 規定以慢速開始的過渡效果(等於 cubic-bezier(0.42,0,1,1))。
ease-out 規定以慢速結束的過渡效果(等於 cubic-bezier(0,0,0.58,1))。
ease-in-out 規定以慢速開始和結束的過渡效果(等於 cubic-bezier(0.42,0,0.58,1))。
cubic-bezier(n,n,n,n) 在 cubic-bezier 函數中定義本身的值。可能的值是 0 至 1 之間的數值。

Animation

建立動畫github

說明
animation-name 指定要綁定到選擇器的關鍵幀的名稱
animation-duration 動畫指定須要多少秒或毫秒完成
animation-timing-function 設置動畫將如何完成一個週期
animation-delay 設置動畫在啓動前的延遲間隔。
animation-iteration-count 定義動畫的播放次數。infinite指定動畫應該播放無限次(永遠)
animation-direction 指定是否應該輪流反向播放動畫。
animation-fill-mode 規定當動畫不播放時(當動畫完成時,或當動畫有一個延遲未開始播放時),要應用到元素的樣式。
animation-play-state 指定動畫是否正在運行或已暫停。

animation-timing-function

描述
linear 動畫從頭至尾的速度是相同的。
ease 默認。動畫以低速開始,而後加快,在結束前變慢。
ease-in 動畫以低速開始。
ease-out 動畫以低速結束。
ease-in-out 動畫以低速開始和結束。
cubic-bezier(n,n,n,n) 在 cubic-bezier 函數中本身的值。可能的值是從 0 到 1 的數值。

animation-direction

描述
normal 默認值。動畫按正常播放。
reverse 動畫反向播放。
alternate 動畫在奇數次(一、三、5...)正向播放,在偶數次(二、四、6...)反向播放。
alternate-reverse 動畫在奇數次(一、三、5...)反向播放,在偶數次(二、四、6...)正向播放。

animation-fill-mode

描述
none 默認值。動畫在動畫執行以前和以後不會應用任何樣式到目標元素。
forwards 在動畫結束後(由 animation-iteration-count 決定),動畫將應用該屬性值。
backwards 動畫將應用在 animation-delay 定義期間啓動動畫的第一次迭代的關鍵幀中定義的屬性值。這些都是 from 關鍵幀中的值(當 animation-direction 爲 "normal" 或 "alternate" 時)或 to 關鍵幀中的值(當 animation-direction 爲 "reverse" 或 "alternate-reverse" 時)。
both 動畫遵循 forwards 和 backwards 的規則。也就是說,動畫會在兩個方向上擴展動畫屬性。

animation-play-state

描述
paused 指定暫停動畫
running 指定正在運行的動畫

瀏覽器事件循環機制

瀏覽器界面的背後隱藏着不少用戶感知不到的事件執行機制,包括加載資源,渲染,網絡請求,用戶交互等多種行爲,動畫也是其中的一部分,由於咱們沒法控制行爲的優先級順序,瞭解這些機制對開發怎麼更好使用動畫有好處.web

  1. 全部的任務都被放主線程上運行造成一個執行棧
  2. 同步任務直接執行並阻塞後續任務等待結束,其中遇到一些異步任務會新開線程去執行該任務而後往下執行,異步任務執行完返回結果以後就把回調事件加入到任務隊列(Queue)
  3. 執行棧(execution context stack)全部任務執行完以後,會到任務隊列(Queue)裏提取全部的微任務隊列(micro tasks)事件執行完, 若是在微任務的執行中又加入了新的微任務,也會在這一步一塊兒執行;
  4. 一次循環結束,GUI渲染線程接管檢查,檢測是否有渲染機會( rendering opportunity),渲染機會根據物理環境決定(依賴機子性能,根據屏幕刷新率、頁面性能、頁面是否在後臺運行來共同決定);算法

    • 瀏覽器會盡量的保持幀率穩定,例如頁面性能沒法維持 60fps(每 16.66ms 渲染一次)的話,那麼瀏覽器就會選擇 30fps 的更新速率,而不是偶爾丟幀。
    • 若是瀏覽器上下文不可見,那麼頁面會下降到 4fps 左右甚至更低。
    • 即便知足上面條件依然可能跳過渲染

      a. 瀏覽器判斷更新渲染不會帶來視覺上的改變。promise

      b. 幀動畫回調爲空瀏覽器

  5. 若是本輪不渲染則推遲也不會執行下面的操做,多個任務會合併到下一輪可渲染的時候,也有利於優化它們之間狀態的合併或者重合,互相抵消等而出現的渲染消耗
  6. 對於須要渲染的文檔,網絡

    • 若是窗口的大小發生了變化,執行監聽的 resize 方法。
    • 若是頁面發生了滾動,執行 scroll 方法。
    • 執行幀動畫回調,也就是 requestAnimationFrame 的回調。
    • 執行 IntersectionObserver 的回調。
  7. 從新渲染繪製用戶界面。
  8. 判斷異步隊列是否都爲空,若是是的話,則進行 Idle 閒置週期的算法,判斷是否要執行 requestIdleCallback的回調函數。

瀏覽器會在保持任務順序的前提下,可能分配四分之三的優先權給用戶交互行爲(鼠標和鍵盤事件),保證用戶的輸入獲得最高優先級的響應,而剩下的優先級交給其餘 Task,而且保證不會「餓死」它們。框架

對於resizescroll來講,並非到了這一步纔去執行滾動和縮放,瀏覽器會保存一個 pending scroll event targets,等到事件循環中的 scroll這一步,去派發一個事件到對應的目標上,驅動它去執行監聽的回調函數而已。resize也是同理。異步

requestAnimationFrame

/**
 * 你但願執行一個動畫,而且要求瀏覽器在下次重繪以前調用指定的回調函數更新動畫
 * @param callback
 * @return 請求 ID
 */
window.requestAnimationFrame(callback)
描述
callback 下一次重繪以前更新動畫幀所調用的函數。該回調函數會被傳入DOMHighResTimeStamp參數,該參數與performance.now()的返回值相同,它表示requestAnimationFrame()開始去執行回調函數的時刻。
返回值 一個 long 整數,請求 ID ,是回調列表中惟一的標識。是個非零值,沒別的意義。你能夠傳這個值給 window.cancelAnimationFrame() 以取消回調函數。

回調函數執行次數一般是每秒60次,但在大多數遵循W3C建議的瀏覽器中,回調函數執行次數一般與瀏覽器屏幕刷新次數相匹配。爲了提升性能和電池壽命,所以在大多數瀏覽器裏,當requestAnimationFrame() 運行在後臺標籤頁或者隱藏的iframe裏時,requestAnimationFrame() 會被暫停調用以提高性能和電池壽命。函數

回調函數會被傳入DOMHighResTimeStamp參數,DOMHighResTimeStamp指示當前被 requestAnimationFrame() 排序的回調函數被觸發的時間。在同一個幀中的多個回調函數,它們每個都會接受到一個相同的時間戳,即便在計算上一個回調函數的工做負載期間已經消耗了一些時間。該時間戳是一個十進制數,單位毫秒,最小精度爲1ms(1000μs)。

DOMHighResTimeStamp 是一個double類型,用於存儲時間值。該值能夠是離散的時間點或兩個離散時間點之間的時間差。T單位爲毫秒 ms (milliseconds) ,應準確至5微秒 µs (microseconds)。可是,若是瀏覽器沒法提供準確到5微秒的時間值(例如,因爲硬件或軟件的限制), 瀏覽器能夠以毫秒爲單位的精確到毫秒的時間表示該值。

requestAnimationFrame VS 定時器

咱們分別用兩個API實現同一個動畫效果,看看他們表現怎麼樣

setTimeout

const gap = 16.6
let num = 0
let timer

function run() {
    timer = setTimeout(() => {
        num++
        document.body.style.background = num % 2 ? "red" : "blue"
        console.log(num)
        num < 30 && run()
    }, gap)
}
run()

image

requestAnimationFrame

let num = 0

function run() {
    window.requestAnimationFrame(() => {
        num++
        document.body.style.background = num % 2 ? "red" : "blue"
        console.log(num)
        num < 30 && run()
    })
}
run()

image

結論

setTimeout存在不繪製的狀況,視覺上看就是掉幀的情形,而requestAnimationFrame 會規律繪製界面,緣由在於通常狀況下, 瀏覽器的幀率跟屏幕幀率一致, 基本都是60, 也就是16ms左右會刷新一次.定時器只是計時完畢把對應任務添加處處理隊列,依然要等執行棧空閒纔會去提取隊列執行,這些形成的結果就是

  • 若是定時器時間小於幀率,在下一次渲染以前已經執行過屢次定時器回調
  • 定時器回調會被主線程其餘任務阻塞執行,每次時間偏差會影響後續執行時間

這兩個影響形成用定時器作動畫會常常傳畫面掉幀或者速率不正常的情形.

requestAnimationFrame是在瀏覽器在下次重繪以前調用,即它的調用時機由系統本身把握,能夠保證在閒置時間內執行,還有一個優勢是當頁面切換其餘應用或者隱藏以後會暫停調用以提高性能和電池壽命。

還有另外一個定時器setInterval也有一些問題

  • 累計效應,若是執行棧阻塞時間足夠長以致於隊列中已經存在多個setInterval的對應任務的狀況,執行時間會遠低於開發者指望的結果;
  • 部分瀏覽器(如Safari等)滾動過程當中執行JS,容易形成卡頓和未知錯誤;
  • 瀏覽器最小化顯示時setInterval會繼續執行,可是對應任務會等到瀏覽器還原再一瞬間所有執行;

requestIdleCallback(實驗中)

此功能某些瀏覽器尚在開發中,請參考瀏覽器兼容性表格以獲得在不一樣瀏覽器中適合使用的前綴。因爲該功能對應的標準文檔可能被從新修訂,因此在將來版本的瀏覽器中該功能的語法和行爲可能隨之改變。
/**
 * 將在瀏覽器的閒置時段內調用的函數排隊
 * @param callback
 * @param options 
 */
window.requestIdleCallback(callback[, options])
描述
callback 一個在事件循環空閒時即將被調用的函數的引用。函數會接收到一個名爲 IdleDeadline的參數,這個參數能夠獲取當前空閒時間以及回調是否在超時時間前已經執行的狀態。
options(可選) timeout:若是指定了timeout並具備一個正值,而且還沒有經過超時毫秒數調用回調,那麼回調會在下一次空閒時期被強制執行,儘管這樣極可能會對性能形成負面影響。

React實現了一套相似的時間分片渲染機制

摘要

web開發使用這個API可以協同調度後臺任務,這樣它們就不會給共享相同循環階段的其餘高優先級任務,例如輸入處理,動畫和幀合成帶來延遲.用戶代理可以基於它對當前調度任務的瞭解,垂直同步(vsync?)延遲,用戶交互等等更好肯定何時適合運行後臺任務,而不會在動畫和輸入響應引發用戶可察覺的延遲或閃爍(jank?).所以,當瀏覽器將處於閒置的時候使用這個API可以更適當的調度後臺任務.

閒置週期

在給定幀內完成輸入處理,渲染和合成以後.用戶代理的主線程一般處於閒置直到下一幀開始,另外一個等待任務會有資格參與運行.或者接收到用戶輸入,這規範提供一種方式在其餘閒置時間經由requestIdleCallback API去調度執行回調

經過requestIdleCallback API回調的方式能夠在用戶代理定義的閒置週期執行,它會給予一個符合的截止日期對應當前閒置週期的結束時間.這決定用戶代理怎麼定義閒置週期的構成,可是預期它們會發生在靜止期間,瀏覽器處於閒置週期.

一個閒置週期的例子是在動態動畫處於將給定幀提交到屏幕和開始處理下一幀之間的時間裏

Figure 1 Example of an inter-frame idle period

image

在動態動畫和屏幕更新期間,這樣的閒置時間會頻繁出現,但一般都很短(即,小於16ms的設備與60Hz的垂直同步週期)

注意

web開發應該仔細考慮在閒置回調期間內全部由操做完成的工做.一些操做例如promise解析或觸發頁面佈局,可能致使隨後的任務會在閒置週期完成後才調度,在這種狀況下,應用程序應該在截止日期到期以前完成這些額外的工做,從而容許在下一個框架截止日期以前執行這些操做。

Figure 2 Example of an idle period when there are no pending frame updates

image

另外一個例子是用戶代理在閒置週期內但沒有屏幕更新發生,在這種狀況下,用戶代理可能沒有能夠綁定閒置期結束的後續任務,以免在不可預測的任務中形成用戶可察覺的延遲例如用戶輸入處理,這些閒置時間的長度應該被限制到50ms的最大值,一旦一個閒置週期已經完成後用戶代理能夠立馬調度另外一個閒置週期(若是他保持閒置),如圖2所示,以使後臺工做在更長閒置時間內繼續發生。

在閒置週期內用戶代理會以先進先出的順序運行回調直到閒置週期結束或者沒有更多的閒置回調有資格運行.就其自己而論,用戶代理並不須要在一個閒置週期內運行完當前發佈的全部閒置回調.任何剩餘的閒置任務均可以在下一個閒置期間運行。

注意

爲開發者們提供最佳性能,鼓勵消除沒必要要的回調(例如requestAnimationFrame, setTimeout等等),他們並不執行有意義的工做,不要保持這些回調觸發並等待事件的響應.取而代之的是根據須要去調度它們以便在它們可用時對事件做出反應,這種模式提升了總體效率而且容許用戶代理去調度長閒置週期(直到50ms)可用於高效地執行大塊的後臺工做。

由於還沒標準化,因此更新細節能夠查看 這裏

相關文章
相關標籤/搜索