JavaScript是如何工作的: CSS 和 JS 動畫底層原理及如何優化它們的性能

来源:https://www.cnblogs.com/fundebug/archive/2019/01/18/js_css_animation.html
-Advertisement-
Play Games

摘要: 理解瀏覽器渲染。 原文: "JavaScript是如何工作的: CSS 和 JS 動畫底層原理及如何優化它們的性能" 作者: "前端小智" "Fundebug" 經授權轉載,版權歸原作者所有。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 13 篇。 如果你錯過了前面的 ...


摘要: 理解瀏覽器渲染。

Fundebug經授權轉載,版權歸原作者所有。

這是專門探索 JavaScript 及其所構建的組件的系列文章的第 13 篇。

如果你錯過了前面的章節,可以在這裡找到它們:

概述

你肯定知道,動畫在創建引人註目的 Web 應用程式中扮演著重要的角色。隨著用戶越來越多地將註意力轉移到用戶體驗上,商戶開始意識到完美、愉快的用戶體驗的重要性,結果 Web 應用程式變得越來越重,並具有更動態交互的 UI。這一切都需要更複雜的動畫,以便用戶在整個過程中更平穩地進行狀態轉換。今天,這甚至不被認為是什麼特別的事情。用戶正變得越來越挑剔,預設情況下,他們期望的是具有高響應性和交互性的用戶界面。

然而,界面的動畫化並不一定是簡單的。什麼是動畫,什麼時候該用動畫,動畫應該有什麼樣的視頻效果,這些都是棘手的問題。

JavaScript 和 CSS 動畫比較

創建 Web 動畫的兩種主要方法是使用JavaScript和 CSS。選擇哪種沒有對或錯,這完全取決於你想要達到的效果。

CSS 動畫

用CSS製作動畫是讓元素在屏幕上移動的最簡單方法。

這裡將從如何讓元素在 X 和 Y 軸上移動 50px 簡單示例開始,通過持續 1 秒的 CSS 過渡來移動元素。

.box {
  -webkit-transform: translate(0, 0);
  -webkit-transition: -webkit-transform 1000ms;

  transform: translate(0, 0);
  transition: transform 1000ms;
}

.box.move {
  -webkit-transform: translate(50px, 50px);
  transform: translate(50px, 50px);
}

當元素加上 move 類時,改變 transform 的值然後開發發生過渡效果。

除了轉換持續時間外,還有 easing 屬性,這實際上就是動畫的運動速度方式,該參數會在之後詳細介紹。

如果像上面的代碼片段一樣,創建單獨的 CSS 類來實現動畫,當然也可以使用 JavaScript 來切換每個動畫。

如下元素:

<div class="box">
  Sample content.
</div>

然後,使用 JavaScript 來切換每個動畫。

var boxElements = document.getElementsByClassName('box'),
    boxElementsLength = boxElements.length,
    i;

for (i = 0; i < boxElementsLength; i++) {
  boxElements[i].classList.add('move');
}

上面的代碼片段是為所有包含 box 類的元素為其添加 move 類以觸發動畫。

這樣做可以為你的應用提供良好的平衡。 你可以專註於使用 JavaScript 管理狀態,只需在目標元素上設置適當的類,讓瀏覽器處理動畫。 如果沿著這條路線前進,你可以在元素上監聽 transitionend 事件,但前提是放棄舊版 Internet Explorer 的支持:

監聽 transitionend 觸發的事件如下所示:

var boxElement = document.querySelector('.box');
boxElement.addEventListener('transitionend', onTransitionEnd, false);

function onTransitionEnd() {
  // Handle the transition finishing.
}

除了使用 CSS 過渡之外,你還可以使用 CSS 動畫,CSS 動畫可以讓你更好地控制單獨的動畫關鍵幀,持續時間以及迴圈次數。

關鍵幀用於指示瀏覽器 CSS 屬性在給定時間點上應有的 CSS 屬性,然後填充空白。

來個簡單的例子:

.box {
  /* 動畫的名字 */
  animation-name: movingBox;

  /* 動畫的持續時間 */
  animation-duration: 2300ms;

  /* 動畫的運行次數 */
  animation-iteration-count: infinite;

  /* 設置對象動畫在迴圈中是否反向運動的方法 */
  animation-direction: alternate;
}

@keyframes movingBox {
  0% {
    transform: translate(0, 0);
    opacity: 0.4;
  }

  25% {
    opacity: 0.9;
  }

  50% {
    transform: translate(150px, 200px);
    opacity: 0.2;
  }

  100% {
    transform: translate(40px, 30px);
    opacity: 0.8;
  }
}

效果示例: https://sessionstack.github.i...

使用CSS動畫,你可以獨立於目標元素定義動畫本身,並使用 animation-name 屬性來選擇所需的動畫。

CSS 動畫在某種程度仍然需要加瀏覽器首碼的,在 Safari、Safari Mobile 和 Android 中都使用了 -webkit。 Chrome、 Opera、Internet Explorer 和 Firefox 都不需要添加首碼。許多工具可以幫助你創建所需 CSS 的首碼,這樣就不需要在源文件中帶樣式首碼。

JavaScript 動畫

和 CSS 過渡或者 CSS 動畫相比,使用 JavaScript 創建動畫更加複雜,但它通常為開發人員提供了更強大的功能。

JavaScript 動畫是作為代碼的一部分內聯編寫的。你還可以將它們封裝在其他對象中。以下為用 JavaScript 來實現最開始的 CSS 過渡的代碼:

var boxElement = document.querySelector('.box');
var animation = boxElement.animate([
  {transform: 'translate(0)'},
  {transform: 'translate(150px, 200px)'}
])

animation.addEventListener('finish', function() {
  boxElement.style.transform = 'translate(150px, 200px)';
})

預設情況下,Web 動畫僅修改元素的展示效果。 如果要將對象停留在移動後的位置,則應在動畫完成時修改其基礎樣式。 這就是為什麼在上面的例子中監聽 finish 事件,並將 box.style.transform 屬性設置為 translate(150px, 200px),該屬性值和 CSS 動畫執行的第二個樣式轉換是一樣的。

使用 JavaScript 動畫,你可以在每一步完全控制元素的樣式。 這意味著你可以放慢動畫速度,暫停動畫,停止它們,翻轉它們,並根據需要操縱元素。 如果你正在構建複雜的面向對象的應用程式,這尤其有用,因為你可以正確地封裝你想要的動畫行為。

代碼部署後可能存在的BUG沒法實時知道,事後為瞭解決這些BUG,花了大量的時間進行log 調試,這邊順便給大家推薦一個好用的BUG監控工具Fundebug

Easing 定義

自然過渡效果會讓你的用戶對你的 Web 應用程式感覺更舒服,從而帶來更好的用戶體驗。

當然,沒有任何東西從一個點到另一個點線性移動。 實際上,當事物在我們周圍的物理世界中移動時,事物往往會加速或減速,因為我們不是在真空中,並且有不同的因素會影響這一點。 人類的大腦會期望感受這樣的移動,所以當為網路應用製作動畫的時候,利用此類知識會對自己會有好處。

以下是一些術語需要瞭解一下:

  • ease-in — 相對於勻速,開始的時候慢,之後快
  • ease out — 相對於勻速,開始時快,結束時候間慢
  • ease-in-out — 相對於勻速,開始和結束都慢)兩頭慢

Easing 關鍵字

CSS 過渡和動畫允許你選擇要使用的 easing 類型。 不同的關鍵字會影響動畫的 easing,你也可以完全自定義 easing 方法。

以下為可以選擇用來控制 easing 的 CSS 關鍵字:

  • linear
  • ease-in
  • ease-out
  • ease-in-out

讓我們深入來瞭解一下這幾個兄弟,並看它們各自展示的效果是怎麼樣。

Linear 動畫

easing 方法的的預設為 linear,以下為 linear 過渡效果的圖示:

隨著時間增加,值等比增加,使用 linear 動效,會讓動畫不自然,一般來說,避免使用 linear 動效。

以下是如何實現簡單的線性動畫:

transition: transform 500ms linear;

Ease-out 動畫

如前所述,與線性動畫相比,easing out 動畫開始時快,結束時候間慢,過渡效果的圖示如下:

一般來說,easing out過渡效果是最適合做界面體驗的,因為快速地啟動會給人以快速響應的動畫的感覺,而結束時讓人感覺很平滑這得歸功於不一致的移動速度。

有很多方法可以實現 ease-out 效果,但最簡單的是 CSS 中的 ease-out 關鍵字:

transition: transform 500ms ease-out;

Ease-in 動畫

ease-out 動畫相反-開始時快,結束時候間慢,過渡效果圖如下:

ease-out 動畫相比, ease-in 可能會讓人感到不尋常,由於啟動緩慢給人以反應卡頓的感覺,因此會產生一種無反應的感覺。 動畫結束很快也會產生一種奇怪的感覺,因為整個動畫正在加速,而現實世界中的物體在突然停止時往往會減速。

ease-outlinear 動畫類似,使用 CSS 關鍵字來實現 ease-in 動畫:

transition: transform 500ms ease-in;

Ease-in-out 動畫

該動畫為 ease-in 和 ease-out 的合集,過渡效果圖如下:

不要使用太長的動畫持續時間,因為它們會讓你的 UI 感覺沒有響應。

ease-in-out CSS 關鍵字來實現 ease-in-out 動畫:

transition: transform 500ms ease-in-out;

自定義 easing

你也可以定義自己的 easing 曲線,這可以更好地創建自己想要的動畫效果。

實際上, ease-inlinearease 關鍵字映射到預定義 貝塞爾曲線 ,可以在 CSS transitions specificationWeb Animations specification 中查找更多關於貝塞爾曲線的內容。

貝塞爾曲線 (Bézier curves)

Bézier curve(貝塞爾曲線)是應用於二維圖形應用程式的數學曲線。 曲線定義:起始點、終止點(也稱錨點)、控制點。通過調整控制點,貝塞爾曲線的形狀會發生變化。 1962年,法國數學家Pierre Bézier第一個研究了這種矢量繪製曲線的方法,並給出了詳細的計算公式,因此按照這樣的公式繪製出來的曲線就用他的姓氏來命名,稱為貝塞爾曲線

CSS3 transition-timing-function 屬性,其語法如下:

transition-timing-function: linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n);

總而言之可以用cubic-bezier(n,n,n,n)的形式來表示全部的屬性值,這裡就涉及到貝塞爾曲線(Bézier curve)。

讓我們看看貝塞爾曲線的工作原理。 貝塞爾曲線需要四個值,或者更準確地說它需要兩對數字。 每對描述立方貝塞爾曲線控制點的 XY 坐標。貝塞爾曲線的起點有一個坐標 (0, 0) ,結束坐標是 (1, 1)。 你可以設置兩個對號,兩個控制點的 X 值必須在 [0,1] 範圍內,並且每個控制點的 Y 值可以超過 [0,1] 限制,儘管規定不清楚多少。

即使每個控制點的 XY 值稍有變化,也會得到完全不同的曲線。讓我們看兩張貝塞爾曲線的圖,兩張圖相近但坐標的控制結點卻不同。

如您所見,兩張圖有很大的不同, 第一個控制點矢量差為 (0.045,0.183) 矢量差,而第二控制點矢量差為 (-0.427, -0.054)

第二條曲線的樣式為:

transition: transform 500ms cubic-bezier(0.465, 0.183, 0.153, 0.946);

前兩個數字是第一個控制點的 XY 坐標,後兩個數字是第二個控制點的 XY 坐標。

性能優化

當你在使用動畫的時候,你應該維持 60 幀每秒,否則會影響用戶體驗。

和世界上的其他事物一樣,動畫也會有性能的開銷。一些屬性的動畫性能開銷相比其它屬性要小。例如,為元素的 widthheight 做動畫會更改其幾何結構並且可能會造成頁面上的其它元素移動或者大小的改變,這個過程稱為佈局。我們在之前的一篇文章 中更詳細地討論了佈局和渲染。

通常,你應該避免動畫觸發佈局或重繪的屬性。 對於大多數現代瀏覽器,這意味著把動畫局限於 opacitytransform 屬性。

Will-change

你可以使用 will-change 知瀏覽器你打算更改元素的屬性,這允許瀏覽器在進行更改之前進行最適當的優化。但是,不要過度使用 will-change,因為這樣做會導致瀏覽器浪費資源,從而導致更多的性能問題。

will-change 用法如下:

.box {
  will-change: transform, opacity;
}

該屬性在 Chrome, Firefox,Opera 得到很好的相容。

JavaScript 動畫和 CSS 動畫該如果抉擇

  • 根據 Google Developer,渲染線程分為 主線程 (main thread)合成線程 (compositor thread)。如果 CSS 動畫只是改變 transformsopacity,這時整個 CSS 動畫得以在 合成線程 完成(而JS動畫則會在 主線程 執行,然後觸發合成線程進行下一步操作),在 JS 執行一些昂貴的任務時,主線程繁忙,CSS 動畫由於使用了合成線程可以保持流暢
  • 在許多情況下,也可以由合成線程來處理 transformsopacity 屬性值的更改。
  • 對於幀速表現不好的低版本瀏覽器,CSS3可以做到自然降級,而JS則需要撰寫額外代碼。
  • CSS動畫有天然事件支持(TransitionEnd、AnimationEnd,但是它們都需要針對瀏覽器加首碼),JS則需要自己寫事件。
  • 如果有任何動畫觸發繪畫,佈局或兩者,則需要 “主線程” 才能完成工作。 這對於基於 CSS 和 JavaScript 的動畫都是如此,佈局或繪製的開銷可能會使與 CSS 或 JavaScript 執行相關的任何工作相形見絀,這使得問題沒有實際意義。
  • CSS3有相容性問題,而JS大多時候沒有相容性問題。

總結

如果動畫只是簡單的狀態切換,不需要中間過程式控制制,在這種情況下,css 動畫是優選方案。它可以讓你將動畫邏輯放在樣式文件裡面,而不會讓你的頁面充斥 Javascript 庫。然而如果你在設計很複雜的富客戶端界面或者在開發一個有著複雜 UI 狀態的 APP。那麼你應該使用 js 動畫,這樣你的動畫可以保持高效,並且你的工作流也更可控。所以,在實現一些小的交互動效的時候,就多考慮考慮 CSS 動畫。對於一些複雜控制的動畫,使用 javascript 比較可靠。

原文:

https://blog.sessionstack.com...

關於Fundebug

Fundebug專註於JavaScript、微信小程式、微信小游戲、支付寶小程式、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了9億+錯誤事件,付費客戶有Google、360、金山軟體、百姓網等眾多品牌企業。歡迎大家免費試用


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

-Advertisement-
Play Games
更多相關文章
  • 1、在springboto項目中使用thymeleaf標簽,必須先添加依賴,如下。 2、在application.properties中配置一些常用的thymeleaf,如下。 可參考博客:https://blog.csdn.net/ice_lemon_g/article/details/73609 ...
  • 錯誤信息:Exception processing template “/view/df”: Error resolving template “/view/df”, template might not exist or might not be accessible by any of the ...
  • 初學node.js,跟著node入門,操作了一遍。在最後一步,上傳圖片並顯示時遇到報錯 根據報錯信息,查找到相應的代碼, 首先想到的是代碼中是相對路徑,導致不能查找到文件所在的位置,於是將路徑補全 還是同樣的報錯 仔細觀察後發現在路徑名中可能存在的左右反斜杠的問題。即在windows中路徑名間隔符為 ...
  • from: https://freefrontend.com/css-timelines/ https://bootstrapthemes.co/items/resources/timeline/ https://github.com/twbs/bootstrap/releases css: htm ...
  • 互聯網內各網路設備間的通信都遵循TCP/IP協議,利用TCP/IP協議族進行網路通信時,會通過分層順序與對方進行通信。分層由高到低分別為:應用層、傳輸層、網路層、數據鏈路層。發送端從應用層往下走,接收端從數據鏈路層網上走 ...
  • 091-100章總結 091. DOM簡介 什麼是DOM • DOM,全稱Document Object Model文檔對象模型。 • JS中通過DOM來對HTML文檔進行操作。只要理解了DOM就可以隨心所欲的操作WEB頁面。 • 文檔– 文檔表示的就是整個的HTML網頁文檔 • 對象– 對象表示將... ...
  • Document ...
  • 效果展示 包含技術點 1、分片上傳。 2、文件秒傳。 3、文件夾上傳 4、文件續傳。 5、文件拖拽上傳。 組件目錄 實現分析 分片上傳 通過H5 FileUpload對象可以實現文件上傳, mutiple屬性可以支持文件多選。拿到文件對象後,調用完整的分片上傳流程:計算MD5-添加文件-獲取鑒權信息 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...