Web高性能動畫及渲染原理(1)CSS動畫和JS動畫

来源:https://www.cnblogs.com/dashnowords/archive/2019/10/15/11680067.html
-Advertisement-
Play Games

示例代碼托管在: "http://www.github.com/dashnowords/blogs" 博客園地址: "《大史住在大前端》原創博文目錄" 華為雲社區地址: "【你要的前端打怪升級指南】" [TOC] 一. CSS動畫 和 JS動畫 Web動畫的本質是元素 狀態改變造成的樣式變更 ,CS ...


目錄

示例代碼托管在:http://www.github.com/dashnowords/blogs

博客園地址:《大史住在大前端》原創博文目錄

華為雲社區地址:【你要的前端打怪升級指南】

一. CSS動畫 和 JS動畫

Web動畫的本質是元素狀態改變造成的樣式變更,CSS動畫和JS動畫的區別並不是由語言來決定的,而是由兩者的特點和適用場景來判斷的。CSS動畫簡潔高效,提升交互體驗而編寫的代碼可以輕鬆地和主要業務邏輯之間實現隔離,開發中建議優先使用;而當你需要更豐富的緩動函數,多對象關聯動畫或是需要在動畫執行的特定時間點關聯一些其他的業務邏輯等需要細節控制的場景中,JS動畫就會顯得更加清晰且易維護,兩者從來都不是非黑即白的選項。

1.1 CSS動畫

CSS動畫通常指使用transition實現的過渡動畫和使用animation來實現的關鍵幀動畫

transition動畫

transition動畫也被稱為“簡易補間動畫”,需要提供起始和結束兩個關鍵幀,瀏覽器才能夠完成樣式差異比對並計算出對應的過渡動畫。開發者編寫的CSS代碼會在渲染之前被瀏覽器使用(也就是生成CSSOM的過程),所以對於被渲染出來的元素而言,首屏渲染的結果就可以被當做是起始關鍵幀,那麼結束關鍵幀從哪裡來?首先通過JS腳本來修改指定元素的樣式或是類名是可行的,另一種方式就是利用帶有交互事件屬性的CSS偽類(例如:hover或是:focus),當對應的事件觸發時,新的樣式就會作用於指定元素,這種特性也可以理解為CSS語法中的事件回調機制。當結束關鍵幀被創建後,瀏覽器就可以自動計算兩者之間的差異並完成過渡動畫。

transition動畫的要點就是具有樣式差異的兩個關鍵幀。如果CSS代碼中只包含一般的靜態選擇器(指CSS代碼中不包含能夠造成HTML元素狀態變更的選擇器),那麼被渲染出的元素在整個生命周期中就只會擁有一個關鍵幀,也就是首次被渲染時的樣式,而1個關鍵幀或是2個沒有樣式差異的關鍵幀都無法進行插值計算,這也就不難理解為什麼首屏渲染時transition不會生效了。

所以transition動畫比較適合被用來實現指定元素在兩個明確的包含樣式差異的狀態之間往複切換的場景,像是滑鼠的移入移出,元素的聚焦失焦等。

animation動畫

animation動畫需要使用@keyframes關鍵詞先將動畫過程抽象出來,然後將其關聯給指定元素的animation屬性,它可以看做是transition動畫的加強版。

使用@keyframes定義動畫時通常需要指定fromto兩個狀態(也可以使用0100%),這意味著開發者只要按照語法要求去定義一個動畫過程,它至少會包含兩個關鍵幀,所以即使沒有CSS偽類或JS腳本的幫助,依然可以獨立實現動畫。如果沒有定義from起始關鍵幀的樣式,animation動畫也不會出錯,它會預設以指定元素在動畫開始時刻的樣式作為起始關鍵幀,並結合to定義的結束關鍵幀和指定元素的animation定製參數來完成補間動畫的計算,所以即使像下麵這樣的簡陋寫法在首屏渲染時依然可以生效:

<style>
    .main{
        height:100px;
        width:100px;
        animation:fadeIn 2s linear;
    }
    @keyframes fadeIn{
        to{
            background-color:yellowgreen;
        }
    }
</style>
<body>
   <div class="main"></div>
</body>

其次,和transition過渡動畫不同的是,animation動畫在不存在樣式差異的關鍵幀之間也會執行動畫,附件的示例demo中已經展示了上述幾種不同動畫實現方式,你可以使用Chrome DevTools中的Animations面板中來查看動畫的觸發效果:

最後,animation動畫最顯著的特點就是起止狀態之間可以定義多個中間幀,這部分就不再贅述。綜上可知,animation是一種強制執行的動畫,既對transition過渡動畫失效的場景進行了補充實現,同時也增加了動畫細節的可定製性(例如迴圈動畫或往複動畫的實現),但它的功能擴展仍然是針對單過程動畫的。關於animation動畫還不熟悉的讀者可以查看【MDN-CSS Animations】

1.2 JS動畫

JS動畫並不是指Web Animations API(MDN文檔——Web Animations API ),它畢竟還只是個草案,瞭解一下即可。本節所說的JS動畫,既包括在腳本中修改元素類名或動畫樣式的方式,也包括區別於【關鍵幀動畫】的另一種形式——【逐幀動畫】。逐幀動畫不再藉助瀏覽器內部的插值機制來生成渲染畫面,而是將對應的邏輯在JavaScript中實現,每一幀的狀態都由JS來計算生成,然後藉助requestAnimationFrame來將動畫中的每一幀傳遞到渲染管線中,你可以使用任何自定義的時間函數來執行動畫,也可以同時方便地管理多個對象的多個不同動畫,另外動畫的進度也是全生命周期可感知的(CSS動畫只有animationstartanimationend等少量的事件),你可以自由地實現動畫暫停或者恢復,又或者是在動畫執行到某一特定時刻時觸發其他的邏輯,很明顯,JS動畫在細節控制能力、過程管理能力以及多對象管理能力上都要比純CSS動畫更強大,但隨之而來的複雜性也是必須要付出的代價,另一方面,JS代碼運行在主線程之中,主線程的實時工況會對動畫的流暢度造成極大影響,而CSS動畫則不必擔心。

以一個列表項的渲染動畫為例,通常都會採用階梯交錯動畫(也稱為stagger動畫)來實現,階梯交錯動畫中,每一個元素執行的動畫實際上是一樣的,但是需要在前一個元素的動畫過程執行到特定時間點時自己才能開始執行動畫,後續的元素依次類推,就需要為每一個動畫執行項的animation屬性設置遞增的delay值,這樣的需求使用原生CSS既難編寫也難維護,它通常需要藉助預編譯器才能夠實現,但是如果在JS腳本中來完成相同的設定,相信大部分前端開發者都可以輕鬆做到。

1.3 小結

所以綜上可知,動畫的編寫姿勢,實際上就是在CSS的簡潔性和JS的細節控制力之間找到一個平衡點。CSS動畫可以使用著名的animate.css預設動畫庫,而JS動畫可以藉助velocity.js來實現,當然他們都不是唯一的選擇。

二. 使用Velocity.js實現動畫

velocity.js是一個非常易用的輕量級動畫庫,它包含了jQuery$.animate( )方法的全部功能,但是比jQuery更流暢。velocity.js的調用方式非常簡單,既支持全局函數的形式調用,也支持對象方法的形式調用,在源碼的主文件src/velocity.ts中可以看到下麵的代碼:

if (window) {
    const jQuery: {fn: any} = (window as any).jQuery,
        Zepto: {fn: any} = (window as any).Zepto;

    patchFn(window, true);
    patchFn(Element && Element.prototype);
    patchFn(NodeList && NodeList.prototype);
    patchFn(HTMLCollection && HTMLCollection.prototype);

    patchFn(jQuery, true);
    patchFn(jQuery && jQuery.fn);

    patchFn(Zepto, true);
    patchFn(Zepto && Zepto.fn);
}

也就是說無論你使用原生JavaScript語法,還是項目中已經引用了jQueryZepto,都可以在返回的結果集上以對象方法的形式來調用velocity函數(當然也可以用靜態方法的形式來調用),velocity方法具有多個方法重載,一般形式為接收兩個參數,第一個參數是下一個關鍵幀的樣式,它和CSS中定義關鍵幀沒什麼本質區別,第二個參數是對動畫細節的定製,當多次調用velocity對象方法時就可以實現多步驟動畫的效果,所以在適合的場景中下麵的調用都是合法的:

let element = document.querySelector('div');

//全局函數
Velocity(element, {width:200},{duration:2000});

//原生節點集合的對象方法調用
element.velocity({width:200},{duration:2000});

//jQuery或Zepto中的調用
$(element).velocity({width:200},{duration:2000});
$('div').velocity({width:200},{duration:2000});

//多步驟動畫
$('div')
    .velocity({width:200},{duration:2000})
    .velocity({height:100},{duration:2000})
    .velocity({backgroundColor:'#3498db'},{duration:2000});

velocity.jsV2版本還處在beta階段,API文檔需要在官方倉庫的wiki中查看【velocity.js V2文檔】,它提供的主要擴展能力如下:

  • 事件鉤子

    熟悉現代SPA開發的小伙伴肯定不會對事件鉤子感到陌生,類組件中的生命周期鉤子就是這種形式,當用戶希望某些自定義方法可以在特定時刻運行時,就可以使用velocity中的事件鉤子將自定義方法和動畫的執行關聯起來,很明顯,這種機制的存在增加了動畫的交互和感知性,開發者可以在各個感興趣的階段鉤入自己期望運行的函數。velocity.js中提供的事件鉤子包括:begin(在動畫開始時觸發),complete(動畫結束時觸發),progress(動畫過程中觸發),progress鉤子每次執行時可以獲取到動畫執行情況的細節,例如元素的引用、完成進度的百分比、剩餘的時間以及和緩動函數有關的數據:

    element.velocity({
        width:100
    },{
        begin:function(){/*...*/},
        progress:function(elements, percentComplete, remaining, tweenValue, activeCall){},
        complete:function(){/*...*/}
    });
  • 動畫的編排和調控

    velocity.js可以很方便地對有約束關係的多個動畫進行管理和編排。例如通過配置queue:String參數,就可以同時維護多個隊列,以便同時管理多個併發的順序執行隊列;配置stagger:Number參數,就可以解決上一節中提到的階梯交錯動畫的場景;speed:Number參數可以改變動畫執行的速度;loop可以實現往返動畫;repeat可以實現單向重覆動畫;例如前一節中提及的階梯交錯動畫就可以用下麵的代碼方便地實現:

    document.querySelectorAll('.box').velocity({marginLeft:500},{duration:5000,stagger:200});

    velocity.js中還可以用命令的方式直接控制動畫的執行,命令的使用格式方式為:

    element.velocity(COMMAND_STRING);

    常用的命令字元串包括pause(暫停動畫),resume(恢復暫停的動畫),stop(停止動畫並保持當前狀態),finish(結束動畫並應用結束狀態)以及用於註冊自定義命令、自定義緩動函數甚至自定義預設動畫等的registerXXX命令。例如一段通過按鈕點擊來控制動畫暫停和播放的代碼:

    function bindControl(){
        let flag = true;
        let dom =  document.querySelector('#btn');
        dom.addEventListener('click',function(){
            dom.velocity(flag ? 'pause':'resume');
            flag = !flag;
        });
    }
  • 集成預設動畫

    如果你曾經使用過animate.css預設動畫庫,那麼恭喜你,在velocity你依然可以用同樣的預設動畫名來實現動畫,使用時需要引入額外的補丁庫:

    <script src="./jquery.min.js"></script>
    <script src="./velocity.min.js"></script>
    <script src="./velocity.ui.min.js"></script>

    預設動畫可以直接傳入關鍵詞來使用:

    document.querySelector('.box').velocity('jello'); 
    //也可以覆蓋預設的動畫參數
    document.querySelector('.box').velocity('jello',{ duration:2000 }); 

如果對各種動畫形式還不熟悉,可以直接在【Animate.css官方網站】上直接查看預設動畫的效果。不難看出,純CSS動畫面臨的問題在JavaScript的幫助下基本都得到瞭解決。下一篇中將分析瀏覽器高性能動畫的實現,敬請期待。


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

-Advertisement-
Play Games
更多相關文章
  • 換膚思路: 1.什麼時候換膚? xml載入前換膚,如果xml載入後換膚,用戶將會看見換膚之前的色彩,用戶體驗不好。 2.皮膚是什麼? 皮膚就是apk,是一個資源包,包含了顏色、圖片等。 3.什麼樣的控制項應該進行換膚? 包含背景圖片的控制項,例如textView文字顏色。 4.皮膚與已安裝的資源如何匹配 ...
  • 隊列是常用的數據結構之一,只允許在表的前端(隊頭)進行刪除操作(出隊),在表的後端(隊尾)進行插入操作(入隊)。特點是先進先出,最先插入的元素最先被刪除。 在jQuery內部,隊列模塊為動畫模塊提供基礎功能,負責存儲動畫函數、自動出隊並執行動畫函數,同時還要確保動畫函數的順序執行。 jQuery的靜 ...
  • 為了獲得更好的閱讀體驗,請訪問原地址: "傳送門" 一、React 簡介 React 是什麼 React 是一個起源於 Facebook 的內部項目,因為當時 Facebook 對於市場上所有的 JavaScript MVC 框架都不太滿意,所以索性就自己寫了一套,用來架設 Instagram。做出 ...
  • 上一節我們介紹了vue搭建環境的情況,並使用一種方式搭建了一個項目,在這裡為大家推薦另一種創建項目的方式。 vue init webpack-simple vuedemo02 cd vuedemo02 cnpm install / npm install npm run dev 最後在瀏覽器輸入:l ...
  • JavaScript概述 ECMAScript和JavaScript的關係 1996年11月,JavaScript的創造者 Netscape公司,決定將JavaScript提交給國際標準化組織ECMA,希望這門語言能夠成為國際標準。次年,ECMA發佈262號標準文件(ECMA 262)的第一版,規定 ...
  • call apply bind 返回的是一個修改後的函數。需要另外調用。 ...
  • 一、簡介、使用 1、簡介 Bootstrap 來源於 Twitter,是一款基於 Html、Css、JavaScript 的前端UI框架。可以方便、快速的開發web界面。 教程:https://www.runoob.com/bootstrap/bootstrap-tutorial.html 2、使用 ...
  • 一.父傳子( 父組件 子組件 二.子傳父 子組件 父組件 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...