Houdini's 動畫小程式

強化網頁應用程式動畫

TL;DR:動畫 Worklet 可讓您編寫可執行的命令式動畫 自動評估裝置上是否出現了原生影格速率 能讓動畫更靈活地因應主執行緒的資源浪費情形,而且還能建立連結 不必使用時間捲動畫面動畫小程式提供 Chrome Canary 版本 (位於 「實驗性 Web Platform 功能」,且我們計劃推出 Chrome 71 的來源試用。您可以開始使用 現在,循序漸進地推出進步效果。

另一個動畫 API?

事實上,這只是我們現有的工具的延伸,而且有充分的理由! 讓我們先從一開始。如果要為網路上的任何 DOM 元素建立動畫 目前有兩種 1⁄2 的選項:CSS 轉換 簡單的 A 到 B 轉場效果;CSS 動畫 可能循環、較複雜的時間式動畫和 Web Animations API (WAAPI)。WAAPI 支援矩陣看起來很粗略,不過 郵件正在運送途中在此之前 polyfill

這些方法的共通之處在於無狀態 時間導向。但開發人員嘗試的一些影響 時間導向或無狀態的容器例如,知名的視差捲軸 也就是以捲動為準現在要在網路上導入成效卓越的視差捲動器,可說是無比艱鉅的挑戰。

那無狀態呢?以 Android 裝置上的 Chrome 網址列為例 範例。只要向下捲動,畫面就會從畫面上消失。不過 當您向上捲動時,即使將近半個 下方。動畫不只取決於捲動位置 先前的捲動方向其有狀態

另一個問題是設定捲軸樣式。他們是奇怪一點,或 可能性不足如果我想要貓貓做為捲軸,該怎麼做? 無論您選擇哪種技巧,都能輕鬆建立自訂捲軸 高效能或簡單

重點是困境,不可能 有效導入多數函式都會使用事件和/或 requestAnimationFrame,即使螢幕為每秒影格數,仍會保持 60 FPS 能夠以每秒 90 個影格、120 FPS 或更高速度執行 寶貴的主執行緒影格預算。

「動畫 Worklet」擴充了網頁動畫堆疊的功能, 讓使用者更輕鬆愉快開始使用之前 都能掌握最新的動畫基本概念

關於動畫和時間軸的基本概念

WAAPI 和動畫工作程式充分運用時間軸,方便您 可按照您希望的方式自動化調度管理動畫和效果本節是 快速複習或簡介時間軸,以及時間軸說明與動畫搭配運作的方式。

每份文件都有 document.timeline。文件開始時間為 0 並計算自文件開始儲存以來的毫秒數。所有的運算 文件動畫會根據這個時間軸運作。

為了更具體說明,我們來看看這個 WAAPI 程式碼片段

const animation = new Animation(
  new KeyframeEffect(
    document.querySelector('#a'),
    [
      {
        transform: 'translateX(0)',
      },
      {
        transform: 'translateX(500px)',
      },
      {
        transform: 'translateY(500px)',
      },
    ],
    {
      delay: 3000,
      duration: 2000,
      iterations: 3,
    }
  ),
  document.timeline
);

animation.play();

當我們呼叫 animation.play() 時,動畫會使用時間軸的 currentTime 視為開始時間動畫延遲 3000 毫秒 當時間軸達到「startTime」時,動畫就會開始 (或設為「啟用」)

  • 3000. After that time, the animation engine will animate the given element from the first keyframe (translateX(0)), through all intermediate keyframes (translateX(500px)) all the way to the last keyframe (translateY(500px)) in exactly 2000ms, as prescribed by thedurationoptions. Since we have a duration of 2000ms, we will reach the middle keyframe when the timeline'scurrentTimeisstartTime + 3000 + 1000and the last keyframe atstartTime + 3000 + 2000`。重點是 時間軸可用來控制動畫中的位置!

動畫播放至最後一個主要畫面格後,就會回到第一個主要畫面格 讓主要畫面格同時啟動,並開始播放動畫的下一個疊代作業。這個程序會重複 自我們設定 iterations: 3 以來總共 3 次。如果我們想讓動畫 因此寫入 iterations: Number.POSITIVE_INFINITY接著來介紹 結果

WAAPI 功能非常強大,這個 API 還有其他功能,例如 加/減速、開始偏移、主要畫面格粗細和填充行為 未進一步探討以上內容如果想要瞭解詳情,建議您參閱有關 CSS 秘訣的 CSS 動畫文章

編寫動畫小程式

既然我們已瞭解時間軸的概念,接著就能開始 動畫小程式以及如何使用時間軸設定搞笑設計工具!動畫 Worklet API 不僅以 WAAPI 為基礎,還以擴充式網路為基礎。 中將說明 WAAPI 的運作方式就語法而言,它們明顯相似:

動畫小程式 網路應用程式防火牆
new WorkletAnimation(
  'passthrough',
  new KeyframeEffect(
    document.querySelector('#a'),
    [
      {
        transform: 'translateX(0)'
      },
      {
        transform: 'translateX(500px)'
      }
    ],
    {
      duration: 2000,
      iterations: Number.POSITIVE_INFINITY
    }
  ),
  document.timeline
).play();
      
        new Animation(

        new KeyframeEffect(
        document.querySelector('#a'),
        [
        {
        transform: 'translateX(0)'
        },
        {
        transform: 'translateX(500px)'
        }
        ],
        {
        duration: 2000,
        iterations: Number.POSITIVE_INFINITY
        }
        ),
        document.timeline
        ).play();
        

不同之處在於第一個參數,也就是 worklet 的名稱 就會造成動畫效果

特徵偵測

Chrome 是發布這項功能的第一款瀏覽器,因此請先確定你的 不會預期 AnimationWorklet 在程式碼中。在載入 Worklet 值,我們應該偵測使用者的瀏覽器是否支援 使用簡單的檢查即可 AnimationWorklet

if ('animationWorklet' in CSS) {
  // AnimationWorklet is supported!
}

正在載入小程式

小木屋是 Houdini 任務小組引進的新概念,旨在 新的 API 建構和擴充更加容易稍後我們將詳細介紹 但為了方便起見 輕量執行緒 (例如 worker)。

我們必須確保我們載入了一個名稱為「passthrough」的 Worklet。 再宣告動畫:

// index.html
await CSS.animationWorklet.addModule('passthrough-aw.js');
// ... WorkletAnimation initialization from above ...

// passthrough-aw.js
registerAnimator(
  'passthrough',
  class {
    animate(currentTime, effect) {
      effect.localTime = currentTime;
    }
  }
);

這裡是怎樣的地點?我們使用 AnimationWorklet 的 registerAnimator() 呼叫,將其命名為「passthrough」。 這與我們在上方的 WorkletAnimation() 建構函式中使用的名稱相同。產生 註冊完成後,addModule() 傳回的承諾就會解決, 我們就能開始使用 Worklet 製作動畫

系統會針對「每個影格」呼叫執行個體的 animate() 方法 瀏覽器需要進行算繪,並傳遞動畫時間軸的 currentTime 以及目前正在處理的效果我們只有一個 、KeyframeEffect 和我們使用 currentTime 來設定效果的 localTime,因此這個動畫稱為「直通式」。這段程式碼的觸發條件 而上方的 WAAPI 和 AnimationWorklet 本身都等同於 如同 demo」。

時間

animate() 方法的 currentTime 參數是currentTime 我們傳遞至 WorkletAnimation() 建構函式的時間軸。在前一個 例如,我們剛才將時間傳遞到效果但由於這是 JavaScript 程式碼,我們就可以扭曲時間 💫?

function remap(minIn, maxIn, minOut, maxOut, v) {
  return ((v - minIn) / (maxIn - minIn)) * (maxOut - minOut) + minOut;
}
registerAnimator(
  'sin',
  class {
    animate(currentTime, effect) {
      effect.localTime = remap(
        -1,
        1,
        0,
        2000,
        Math.sin((currentTime * 2 * Math.PI) / 2000)
      );
    }
  }
);

我們會擷取 currentTimeMath.sin(),然後將該值重新對應到 範圍 [0;2000],也就是實際效果定義的時間範圍。現在 動畫看起來不太一樣 已變更主要畫面格或動畫選項。Worklet 程式碼可以是 視任意複雜程度而定 你可以透過程式輔助方式 使用順序和程度

選項比選項

您可以重複使用練習題並變更數字。因此 WorkletAnimation 建構函式可讓您將選項物件傳遞至 Worklet:

registerAnimator(
  'factor',
  class {
    constructor(options = {}) {
      this.factor = options.factor || 1;
    }
    animate(currentTime, effect) {
      effect.localTime = currentTime * this.factor;
    }
  }
);

new WorkletAnimation(
  'factor',
  new KeyframeEffect(
    document.querySelector('#b'),
    [
      /* ... same keyframes as before ... */
    ],
    {
      duration: 2000,
      iterations: Number.POSITIVE_INFINITY,
    }
  ),
  document.timeline,
  {factor: 0.5}
).play();

在這個範例中 這兩個動畫都是透過相同的程式碼驅動,但選項不同。

模擬你所在的州/省!

正如先前所提示,動畫專案希望解決的其中一個主要問題 有狀態動畫動畫工作程式可保留狀態。不過, 主要功能是可以遷移至不同的 甚至為了節省資源 而刪除執行緒或執行緒 時間。為避免狀態遺失,動畫 Worklet 會提供掛鉤 在刪除工作程式「之前」呼叫,您可以使用該程式傳回狀態 物件。當 Worklet 為可組合函式時,該物件會傳遞到建構函式 重新建立初次建立時,該參數會是 undefined

registerAnimator(
  'randomspin',
  class {
    constructor(options = {}, state = {}) {
      this.direction = state.direction || (Math.random() > 0.5 ? 1 : -1);
    }
    animate(currentTime, effect) {
      // Some math to make sure that `localTime` is always > 0.
      effect.localTime = 2000 + this.direction * (currentTime % 2000);
    }
    destroy() {
      return {
        direction: this.direction,
      };
    }
  }
);

每次重新整理這個示範時, 正方形旋轉方向的機率如果瀏覽器拆除 並遷移至其他執行緒 Math.random() 來電建立時通話,可能會突然改變 往上移動即可為了確實避免這種情況,系統會傳回動畫 隨機選擇方向做為 state,並在建構函式中使用 (如有提供)。

引入太空時刻延續:ScrollTimeline

如上一節所示,AnimationWorklet 讓我們可以 以程式輔助方式定義前進時間軸會如何影響 但到目前為止,時間軸一直都是 document.timeline, 可追蹤時間

ScrollTimeline 開啟了無限可能,並讓你能夠播放動畫 不必耗費時間捲動我們會先重複使用 「直通式」這件工作 示範

new WorkletAnimation(
  'passthrough',
  new KeyframeEffect(
    document.querySelector('#a'),
    [
      {
        transform: 'translateX(0)',
      },
      {
        transform: 'translateX(500px)',
      },
    ],
    {
      duration: 2000,
      fill: 'both',
    }
  ),
  new ScrollTimeline({
    scrollSource: document.querySelector('main'),
    orientation: 'vertical', // "horizontal" or "vertical".
    timeRange: 2000,
  })
).play();

我們要建立新的 ScrollTimeline,而不是傳遞 document.timeline。 你可能已經猜到,ScrollTimeline 不使用時間,但 scrollSource 的捲動位置,用來設定 Worklet 中的 currentTime。演唱 捲動至頂端 (或向左) 表示 currentTime = 0,而 捲動至底部 (或右側) 會將 currentTime 設為 timeRange。如果您捲動了這部分 示範 控制紅色方塊的位置

如果您建立的 ScrollTimeline 含有不會捲動的元素, 時間軸的currentTimeNaN。尤其在採用回應式設計時 注意,您應隨時為 NaN 做好準備,做為currentTime。這通常是 可預設為 0。

長久以來,大家都致力於連結動畫和捲動位置。 但除了駭客之外,這種保真度也從未如此 CSS3D 解決方法)。動畫小程式能讓這些特效 而且能以簡單明瞭的方式實作,同時保有高效能例如: 像這樣的視差捲動效果 demo 會示範 現在只要用幾行程式碼就能定義捲動導向的動畫。

深入解析

小程式

工作程式是 JavaScript 內容,具有隔離的範圍和非常小的 API 途徑。小型 API 介面可讓系統進行更積極的最佳化調整 特別是在低階裝置上。此外,Worklet 不限於 特定事件迴圈,但可視需要在執行緒之間移動。這是 特別是 AnimationWorklet 的部分都很重要

合成器 NSync

您可能會發現某些 CSS 屬性能快速建立動畫 而不是某些屬性只需要在 GPU 上進行一些工作即可製作動畫,有些屬性則需要在 GPU 上執行動畫 強制瀏覽器重新調整整份文件的版面配置。

在 Chrome 中 (和其他許多瀏覽器中一樣),我們有一種名為合成器的程序, 而我目前把手上的工作內容簡化 然後使用 GPU 盡可能定期更新螢幕 最好等同於螢幕更新速度 (通常為 60 Hz)。根據 CSS 屬性呈現動畫效果,瀏覽器則只需要 合成器可以正常運作,而其他屬性則需要執行版面配置, 只能由主執行緒執行的作業。視您使用的資源而定 動畫任務就會繫結至 或在與合成器同步的另一個執行緒中執行。

戴在手腕上

通常只有一個合成器程序,可能會在以下位置共用 多個分頁,因為 GPU 是高度依賴的資源。如果合成器 整個瀏覽器在遭到封鎖的情況下會停滯不前,而且無法回應 使用者輸入內容您必須盡全力避免這種情況。這樣一來 Worklet 無法及時傳送合成器所需的資料,以便讓影格轉譯 轉譯方式?

如果發生這種情況,工作小程式依規格允許「slip」。落後 合成器,而且合成器可以重複使用最後一個影格的資料, 請保持畫面更新率親眼看,這看起來像卡頓,但大 瀏覽器仍會回應使用者輸入的內容

結論

AnimationWorklet 有許多面向,可在網路上帶來好處。 明顯的優點,更能掌控動畫和全新的駕駛方式 動畫,可為網頁帶來前所未有的視覺擬真度。但 API 還能讓應用程式更彈性應對卡頓 同時享有所有新的實用功能

動畫小程式目前為 Canary 版,我們的目標主要是 Chrome 71。我們非常期待您精彩的全新網路體驗和聽覺 有哪些地方需要改善此外,您也可以參考 polyfill 會提供相同的 API,但不會區隔效能。

請注意,CSS 轉場效果和 CSS 動畫仍然有效 在使用基本動畫時,這會更加簡單。但如果您想 引人入勝,AnimationWorklet 助你一臂之力!