AMP

amp-animation

說明

定義及顯示動畫。

 

必要指令碼

<script async custom-element="amp-animation" src="https://cdn.ampproject.org/v0/amp-animation-0.1.js"></script>

支援的版面配置

用法

amp-animation 元件可定義及執行自訂動畫和效果。它仰賴 Web Animations API

amp-animation 元件會在 JSON 結構中定義動畫。最上層區段會宣告目標元素、執行條件、時間屬性和 keyframes effect (關鍵影格效果),藉此定義整體動畫。整體程序可以包含在 animations 陣列中定義的任意數量的動畫部分。動畫陣列中的動畫部分可以有自己的目標元素、執行條件、時間屬性和關鍵影格效果。

<amp-animation layout="nodisplay">
  <script type="application/json">
    {
      "selector": "#target-id",
      "duration": "1s",
      "iterations": "4",
      "fill": "both",
      "direction": "alternate",
      "animations": [
        {
          "selector": ".target-class",
          "easing": "cubic-bezier(0,0,.21,1)",
          "keyframes": {
            "transform": "rotate(20deg)"
          }
        },
        {
          "delay": "2s",
          "easing": "cubic-bezier(0,0,.21,1)",
          "keyframes": {
            "transform": "rotate(30deg)"
          }
        }
      ]
    }
  </script>
</amp-animation>

如果動畫使用單一元素和單一關鍵影格效果,則此設定可作為單一動畫定義。

<amp-animation layout="nodisplay">
  <script type="application/json">
    {
      "selector": "#target-id",
      "duration": "1s",
      "keyframes": {"opacity": 1}
    }
  </script>
</amp-animation>

如果動畫使用多個元素,但沒有最上層動畫,則此設定可作為定義陣列。

<amp-animation layout="nodisplay">
  <script type="application/json">
    [
      {
        "selector": ".target1",
        "duration": 1000,
        "keyframes": {"opacity": 1}
      },
      {
        "selector": ".target2",
        "duration": 600,
        "delay": 400,
        "keyframes": {"transform": "scale(2)"}
      }
    ]
  </script>
</amp-animation>

透過 trigger 屬性或 action (動作) 觸發一個或多個動畫的開始。

您可以將透過動作控制的 amp-animation 放置在 DOM 中的任何位置。如果動畫包含 trigger="visibility",則會在父項元素進入可視區域時觸發,並在離開可視區域時暫停。

定義效果

關鍵影格

您必須宣告效果為關鍵影格,才能使用 amp-animations 套用動畫。

您可以在 amp-animation 中以與 MDN 的 Keyframe Formats (關鍵影格格式) 中定義的相同方式指定關鍵影格。您也可以參考在 <style amp-custom><style amp-keyframes> 標記中定義為 CSS 的 @keyframes 名稱。

以下是一些典型的關鍵影格定義範例。

速記物件格式 "to" 格式指定 100% 的最終狀態

{
  "keyframes": {"opacity": 0, "transform": "scale(2)"}
}

速記物件格式 "from-to" 格式指定 0% 和 100% 的開始和最終狀態

{
  "keyframes": {
    "opacity": [1, 0],
    "transform": ["scale(1)", "scale(2)"]
  }
}

速記物件格式 "value-array" 格式指定開始、最終狀態和多個 (等間隔) 位移的多個值

{
  "keyframes": {
    "opacity": [1, 0.1, 0],
    "transform": ["scale(1)", "scale(1.1)", "scale(2)"]
  }
}

陣列格式指定關鍵影格。位移會自動指派為 0%、100% 和介於兩者之間的均勻間隔

{
  "keyframes": [
    {"opacity": 1, "transform": "scale(1)"},
    {"opacity": 0, "transform": "scale(2)"}
  ]
}

陣列格式也可以明確包含 "offset"

{
  "keyframes": [
    {"opacity": 1, "transform": "scale(1)"},
    {"offset": 0.1, "opacity": 0.1, "transform": "scale(2)"},
    {"opacity": 0, "transform": "scale(3)"}
  ]
}

陣列格式也可以包含 "easing"

{
  "keyframes": [
    {"easing": "ease-out", "opacity": 1, "transform": "scale(1)"},
    {"opacity": 0, "transform": "scale(2)"}
  ]
}

使用 @keyframes CSS 規則

<style amp-custom>
  @keyframes keyframes1 {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
</style>

<amp-animation layout="nodisplay">
  <script type="application/json">
    {
      "duration": "1s",
      "keyframes": "keyframes1"
    }
  </script>
</amp-animation>

大多數 CSS @keyframes 符合 Web Animations 規格中的 JSON 內嵌關鍵影格定義,但有以下細微差異

  • 您可能需要供應商前置字首,例如 @-ms-keyframes {}-moz-transform,以獲得廣泛的平台支援。JSON 格式不需要且不允許供應商前置字首,但在 CSS 中可能需要。

  • 在不支援的平台上,當搭配 CSS 中指定的關鍵影格使用 calc()var() 時,amp-animation 的 Polyfills 會失敗。在 CSS 中使用回溯值以避免這種情況。

  • CSS 擴充功能 (例如 width()height()x()y()num()rand()index()length()) 不適用於 @keyframes

關於 prefers-reduced-motion

通常,執行動畫會將元素置於可見狀態來完成,而初始 CSS 會隱藏元素,以便稍後依賴動畫完成。

使用者可以將其裝置設定為使用減少的動畫。使用此選項時,動畫根本不會執行。在這種情況下,您需要停用稍後依賴動畫執行的 CSS 屬性。

您可以將媒體查詢用於此目的。在以下範例中,<amp-animation> 稍後會透過設定 opacity: 1 將元素動畫化為可見狀態。當動畫停用時,元素始終可見

<style amp-custom>
  .my-hidden-element {
    opacity: 1;
  }
  @media not (prefers-reduced-motion) {
    .my-hidden-element {
      opacity: 0;
    }
  }
</style>
<amp-animation layout="nodisplay">
  <script type="application/json">
    [
      {
        "selector": ".my-hidden-element",
        "duration": "1s",
        "keyframes": {"opacity": 1}
      }
    ]
  </script>
</amp-animation>
關鍵影格的允許屬性

amp-animation 元件會限制允許使用的 CSS 屬性,以最佳化效能。以下是允許清單中的屬性

不需要也不允許使用供應商前置字首 CSS 屬性。

時間屬性

最上層動畫和動畫元件可能包含時間屬性。以下是允許的屬性集

屬性 類型 預設值 說明
duration (持續時間) time (時間) 0 動畫持續時間。數值 (以毫秒為單位) 或 CSS 時間值,例如 2s
delay (延遲) time (時間) 0 動畫開始執行前的延遲時間。數值 (以毫秒為單位) 或 CSS 時間值,例如 2s
endDelay (結束延遲) time (時間) 0 動畫完成後且實際視為完成前的延遲時間。數值 (以毫秒為單位) 或 CSS 時間值,例如 2s
iterations (迭代次數) 數字或
"Infinity" 或
"infinite"
1 動畫效果重複的次數。
iterationStart (迭代開始) 數字/CSS 0 效果開始動畫化的時間位移。
easing (緩和) 字串 "linear" 用於縮放時間以產生緩和效果的時間函數
direction (方向) 字串 "normal" "normal"、"reverse"、"alternate" 或 "alternate-reverse" 其中之一。
fill (填滿) 字串 "none" "none"、"forwards"、"backwards"、"both"、"auto" 其中之一。

所有時間屬性都允許直接數值/字串值或 CSS 值。例如,10001s1000m 都是 duration 的有效值。

JSON 中時間屬性的範例

{
  ...
  "duration": "1s",
  "delay": 100,
  "easing": "ease-in",
  "fill": "both"
  ...
}

動畫元件會繼承為最上層動畫指定的時間屬性。

變數與計算運算式

amp-animation 允許將 var()calc()min()max() 運算式用於時間和關鍵影格值。

<amp-animation layout="nodisplay">
  <script type="application/json">
    [
      {
        "selector": ".target-class",
        "duration": "4s",
        "delay": "var(--delay)",
        "--y": "var(--other-y, 100px)",
        "keyframes": {"transform": "translate(calc(100vh + 20px), var(--y))"}
      }
    ]
  </script>
</amp-animation>

您可以宣告 CSS 變數,以透過 var() 運算式用於時間和關鍵影格值。

CSS 變數可用於巢狀動畫,但巢狀動畫可能會覆寫變數的值。

<amp-animation layout="nodisplay">
  <script type="application/json">
    {
      "--delay": "0.5s",
      "--x": "100px",
      "animations": [
        {
          "selector": "#target1",
          "delay": "var(--delay)",
          "--x": "150px",
          "keyframes": {"transform": "translate(var(--x), var(--y, 0px)"}
        },
        ...
      ]
    }
  </script>
</amp-animation>

在以上範例中

  • 巢狀動畫會將變數 --delay 套用至 #target1 動畫的延遲時間。

  • 雖然 --x 會傳播到巢狀動畫中,但會被覆寫。最終的 translate 值為 150px

  • <amp-animation> 元件中未在任何位置指定 --y。如果查詢找不到定義為 <amp style-custom> 標記中的 CSS,則預設為 0px

Polyfills 同時適用於支援平台上的 var()calc()。最佳做法是為 var() 包含預設值。

<amp-animation layout="nodisplay">
  <script type="application/json">
    [
      {
        "selector": ".target-class",
        "duration": "4s",
        "delay": "var(--delay, 100ms)"
      }
    ]
  </script>
</amp-animation>

透過使用 amp-animation 元件中的 --var-name 欄位,覆寫在 <style amp-custom> 標記中指定的目標元素的變數。var() 運算式會先嘗試解析在動畫元件中指定的值,然後解析目標樣式。

CSS 擴充功能

amp-animation 元件提供以下 CSS 擴充功能:rand()num()width()height()x()y()。允許的 CSS 擴充功能在 amp-animation 定義中可使用 CSS 值的所有位置都有效。這包括時間和關鍵影格值。

CSS index() 擴充功能

index() 函數會傳回動畫效果中目前目標元素的索引。當使用 selector 屬性為多個目標動畫化相同效果時,這最為相關。selector 比對到的第一個目標將具有 index 0,第二個目標將具有 index 1,依此類推。

除了其他用途外,此屬性還可以與 calc() 運算式結合以建立交錯效果。例如

{
  "selector": ".class-x",
  "delay": "calc(200ms * index())"
}
CSS length() 擴充功能

length() 函數會傳回動畫效果中目標元素的數量。這在與 index() 結合時最為相關

{
  "selector": ".class-x",
  "delay": "calc(200ms * (length() - index()))"
}
CSS rand() 擴充功能

rand() 函數會傳回隨機 CSS 值。有兩種形式。

不帶引數的形式會傳回介於 0 和 1 之間的隨機數字。

{
  "delay": "calc(10s * rand())"
}

第二種形式有兩個引數,並傳回介於這兩個引數之間的隨機值。

{
  "delay": "rand(5s, 10s)"
}
CSS width()height()x()y() 擴充功能

width()/height()x()/y() 擴充功能會傳回動畫元素或選取器指定的元素的大小或座標。傳回的值以像素為單位,例如 100px

amp-animation 支援以下形式

  • width()height()x()y() - 動畫元素的寬度/高度或座標。

  • 使用選取器,例如 width('.selector')x('.selector') - 選取器指定的元素的尺寸或座標。可以使用任何 CSS 選取器。例如,height('#container > li')

  • 使用最接近的選取器,例如 height(closest('.selector'))y(closest('.selector')) - 最接近的選取器指定的元素的尺寸或座標。

width()height() 對於變形特別有用。lefttop 和類似的 CSS 屬性可以使用 % 值來表示與容器大小成比例的動畫。但是,transform 屬性會以不同的方式解譯 % 值 - 作為所選元素的百分比。因此,width()height() 可用於以容器元素等表示變形動畫。

這些函數可以與 calc()var() 和其他 CSS 運算式結合。例如

{
  "transform": "translateX(calc(width('#container') + 10px))"
}
CSS num() 擴充功能

num() 函數會傳回 CSS 值的數字表示法。例如

  • num(11px) 產生 11
  • num(110ms) 產生 110
  • 等等。

例如,以下運算式會計算與元素寬度成比例的延遲時間 (以秒為單位)

{
  "delay": "calc(1s * num(width()) / 100)"
}

覆寫子目標的效果

使用子目標覆寫在最上層動畫中定義的時間屬性或變數。透過 subtargets: [] 定義子目標 (在與有效 selector 相同的空間中)。依索引或 CSS 選取器指定子目標。

{
  "selector": ".target",
  "delay": 100,
  "--y": "100px",
  "subtargets": [
    {
      "index": 0,
      "delay": 200
    },
    {
      "selector": ":nth-child(2n+1)",
      "--y": "200px"
    }
  ]
}

在以上範例中

  • 最上層動畫會將 ".target" 比對到的目標預設為延遲時間 100"--y"100px

  • "subtargets": [] 包含第一個目標 "index": 0。此定義會將預設延遲時間 100 覆寫為 200

  • "subtargets": [] 包含 "selector": ":nth-child(2n+1)"。此定義會將 --y 變數的預設值 100px 覆寫為 200px

多個子目標可以比對一個目標 selector 元素。

SVG 動畫

SVG 很棒,我們建議您將其用於動畫!

amp-animation 元件支援具有允許清單 CSS 關鍵影格屬性的 SVG 動畫,但有以下細微差異

  • IE/Edge SVG 元素不支援 CSS transform 屬性。雖然 transform 動畫本身是 Polyfill,但樣式表中定義的初始狀態未套用。如果初始變形狀態在 IE/Edge 上很重要,建議透過 SVG transform 屬性複製它。

  • 無法為 IE/Edge Polyfill transform-origin。為了相容性,僅使用預設 transform-origin

  • 使用 CSS transform-box 以避免 transform-origin 解譯問題。請參閱 ChromeSafariFirefox 的問題。

相容性與回溯

使用媒體查詢、支援條件和切換陳述式以獲得平台相容性和回溯選項。

媒體查詢

使用 media 屬性指定媒體查詢。此屬性可以包含 Window.matchMedia API 允許的任何運算式,並對應於 @media CSS 規則。

指定後,動畫元件只會在環境支援指定的 CSS 功能時執行。

Supports (支援) 條件

使用 supports 屬性指定支援條件。supports 屬性包含 CSS.supports API 允許的任何運算式,並對應於 @supports CSS 規則。

指定後,動畫元件只會在環境支援指定的 CSS 功能時執行。

動畫 switch (切換) 陳述式

在某些情況下,您可能需要將條件式動畫與選填預設值合併到單一動畫中。使用 switch 動畫陳述式來定義條件。

{
  // Optional selector, vars, timing
  ...
  "switch": [
    {
      "media": "(min-width: 320px)",
      "keyframes": {...},
    },
    {
      "supports": "offset-distance: 0",
      "keyframes": {...},
    },
    {
      // Optional default: no conditionals
    }
  ]
}

amp-animation 元件會依定義的順序評估 switch 動畫定義。它會執行第一個符合條件的動畫,並忽略其餘動畫。

在以下範例中,如果支援 motion-path 動畫,則會執行 motion-path 動畫,並回溯到 transform (變形)

{
  "selector": "#target1",
  "duration": "1s",
  "switch": [
    {
      "supports": "offset-distance: 0",
      "keyframes": {
        "offsetDistance": [0, "300px"]
      }
    },
    {
      "keyframes": {
        "transform": [0, "300px"]
      }
    }
  ]
}

合併與分割動畫

amp-animation 中定義的動畫可以互相參考。此功能允許將多個 amp-animation 宣告合併為單一動畫。將動畫分割成不同的 amp-animation 元件可重複使用較小的動畫,同時啟用與巢狀相同的效果。

<amp-animation id="anim1" layout="nodisplay">
  <script type="application/json">
    {
      "animation": "anim2",
      "duration": 1000,
      "--scale": 2
    }
  </script>
</amp-animation>

<amp-animation id="anim2" layout="nodisplay">
  <script type="application/json">
    {
      "selector": ".target-class",
      "keyframes": {"transform": "scale(var(--scale))"}
    }
  </script>
</amp-animation>

以上範例動畫將 "anim2" 動畫合併為 "anim1" 的一部分。"anim2" 不需要 selector 目標。在這種情況下,包含的動畫會參考自己的目標。

另一種形式允許包含的動畫提供目標或多個目標。在這種情況下,包含的動畫會針對每個比對到的目標執行。

<amp-animation id="anim1" layout="nodisplay">
  <script type="application/json">
    {
      "selector": ".target-class",
      "animation": "anim2",
      "duration": 1000,
      "--scale": 2
    }
  </script>
</amp-animation>

<amp-animation id="anim2" layout="nodisplay">
  <script type="application/json">
    {
      "keyframes": {"transform": "scale(var(--scale))"}
    }
  </script>
</amp-animation>

在以上範例中,"anim2" 會針對每個比對到的 ".target-class" 執行。在呼叫端動畫中指定的變數和時間屬性會傳遞至合併的動畫。

透過 on action (動作) 觸發

例如

<amp-animation id="anim1" layout="nodisplay">
  ...
</amp-animation>
<button on="tap:anim1.start">Animate</button>

動畫的無障礙考量

如果您使用動畫來傳達意義或內容,請確保也以其他形式為可能無法看到這些動畫的使用者傳達此資訊。在最基本層面,請確保您的文字內容傳達與動畫相同的資訊。例如,如果您使用 <amp-animation> 來說明程序中的步驟順序,請確保也有文字 (在同一個頁面或連結頁面中) 以文字描述相同的步驟順序。

動畫通常無法由使用者暫停/停止。根據動畫的類型、大小以及是否循環/重複,這可能是輕微的分心,或對某些使用者群體造成重大問題 - 特別是當動畫包含快速閃爍的色彩變化時。一般而言,我們建議避免使用大型、無限重複的動畫,除非您確定它們不會對使用者產生負面影響。考慮提供控制項以允許使用者暫停動畫。考慮利用 prefers-reduced-motion 媒體查詢,並且僅在使用者指示偏好減少動態/動畫時,才讓動畫生效。

<amp-animation ... media="not (prefers-reduced-motion: reduce)">
  <!-- this animation will only play if the user has *not*
       expressed a preference for reduced motion -->
  ...
</amp-animation>

您可以更進一步,並提供個別、更細微的回溯動畫,以便在 prefers-reduced-motion: reduce 評估為 true 時生效,或分割出無論媒體功能為何都應發生的較小動畫。

<amp-animation ... media="(prefers-reduced-motion: reduce)">
  <!-- fallback subtle animation effects that only play if the user
       has expressed a preference for reduced motion -->
  ...
</amp-animation>

<amp-animation ...>
  <!-- general/common animation effects that will take effect
       regardless of any user preference for reduced motion -->
  ...
</amp-animation>

如需更多詳細資訊,請參閱 MDN - prefers-reduced-motion 和這篇關於 web.dev - prefers-reduced-motion: Sometimes less movement is more (有時少一點動態效果更好) 的介紹文章。

對於並非純裝飾性/視覺效果,而是實際傳達資訊的動畫,請確保任何重要的文字和圖形/非文字元素都有足夠的色彩對比。如需簡介 (主要圍繞文字對比) 請參閱 web.dev 色彩與對比無障礙功能,如需更多關於非文字元素的詳細資訊,請參閱 Knowbility: Exploring WCAG 2.1 — 1.4.11 Non‑text Contrast (探索 WCAG 2.1 — 1.4.11 非文字對比)

屬性

trigger (觸發條件)

決定何時應觸發動畫。必須設定為 visibility,以便在故事頁面變為可見和啟用狀態時啟動動畫。

layout (版面配置)

應始終為 nodisplay

id (選填)

動畫元件的 id。用於參考動畫並串連一系列動畫。

動作

start (開始)

如果動畫尚未執行,則啟動動畫。時間屬性和變數。可以指定為動作引數。例如 anim1.start(delay=-100, --scale=2)

restart (重新開始)

啟動動畫或重新啟動目前正在執行的動畫。時間屬性和變數。可以指定為動作引數。例如 anim1.start(delay=-100, --scale=2)

pause (暫停)

暫停目前正在執行的動畫。

resume (繼續)

繼續目前正在執行的動畫。

togglePause (切換暫停)

切換暫停/繼續動作。

seekTo (搜尋至)

暫停動畫並搜尋至 time 引數 (以毫秒為單位) 或 percent 引數 (以時間軸中的百分點表示) 指定的時間點。

reverse (反向)

反轉動畫。

finish (完成)

完成動畫。

cancel (取消)

取消動畫。

amp-story 用法

如果您想要搭配 <amp-story> 使用 <amp-animation>,請注意您應改用 <amp-story-animation>。如需如何在 Advanced animations (進階動畫) 文件章節中使用它的詳細資訊。

驗證

請參閱 AMP 驗證器規格中的 amp-animation 規則

需要更多協助嗎?

您已閱讀此文件十幾次,但它實際上並未涵蓋您的所有問題?也許其他人也有相同的感受:在 Stack Overflow 上與他們聯繫。

前往 Stack Overflow
發現錯誤或缺少功能?

AMP 專案非常鼓勵您的參與和貢獻!我們希望您能成為我們開放原始碼社群的持續參與者,但我們也歡迎針對您特別熱衷的問題提供一次性貢獻。

前往 GitHub