AMP

複雜動畫簡介

對於無法透過新增和移除類別驅動的動畫,AMP 提供了數個動畫專用元件。這些元件將 AMP 的原則應用於動畫:它們快速、有效率且以使用者優先。AMP 限制了關鍵影格內允許的 CSS 屬性,但提供了精細控制、無縫動畫和跨瀏覽器相容性等優點,而且無需額外工作。

如果您需要嚴格控制播放,以及同時為多個元素製作動畫的精確時間控制,請使用 amp-animation。

建立基本 AMP 動畫

amp-animation 元件可在 AMP 中使用 Web Animation API

基本的 amp-animation 是一個 JSON 物件,由以下主要部分組成

<amp-animation layout="nodisplay" id="exampleAnimation">
<script type="application/json">
{
 "selector": "#elementID", //select the element to animate
 "duration": "1s", //timing property
 "iterations": 2, //timing property
 "fill": "both", //timing property
 "keyframes": {"opacity": 0, "transform": "scale(2)"} //keyframes
}
</script>
</amp-animation>
<!-- trigger -->
<button on="tap:exampleAnimation.start">

選取器

與 CSS 非常相似,amp-animation 元件透過在 "selector" 欄位中宣告元素的標籤名稱、類別或 ID,將動畫屬性連結到元素。元件會為每個具有宣告的標籤類型或類別名稱的元素製作動畫。使用 ID 可確保您只為單一元素製作動畫。

時間屬性

時間屬性控制動畫的持續時間、播放次數以及關鍵影格的執行方向。

雖然不需要時間屬性,但如果缺少與時間和顯示相關的屬性 (例如 duration (持續時間) 和 fill (填滿)),動畫可能不會執行。

關鍵影格

雖然 CSS 允許您透過轉場效果從一個狀態變形到另一個狀態,但您必須將動畫屬性宣告為關鍵影格才能實作。可用的 amp-animation 用於 GPU 加速屬性,這些屬性不會導致重新版面配置,並且可以在合成器執行緒上製作動畫。這樣可以防止動畫干擾 AMP 和瀏覽器的渲染程序

關鍵影格可以直接在 amp-animation 中定義。

觸發器

觸發器會啟動動畫序列。amp-animation 擴充功能會在 <body> 在頁面上變成可見時,或透過將其連接到 AMP 動作或事件來啟動。

當動畫應在頁面載入後立即執行時 (因為它顯示在「首屏」或頁面的第一個可視區域內),在 <body> 可見時觸發非常有用。動畫透過可見性觸發,方法是將 trigger="visibility" 作為屬性新增至元件。

<amp-animation layout="nodisplay"
    trigger="visibility">
  ...
</amp-animation>

動畫透過為 amp-animation 元件指派 id,並將該 id 連結到所需的事件觸發器 (例如點擊按鈕) 來連接到動作或事件。

<amp-animation layout="nodisplay" id="exampleAnimation">
  ...
</amp-animation>

<button on="tap:exampleAnimation.start">

建構複雜動畫

amp-animation 中建構動畫可以進行精細的控制,而不僅僅是啟動和停止動畫:它還可以暫停、反轉和導向到特定點。您甚至可以將多個動畫串聯在一起,並依序為元素製作動畫。

子目標

相同標籤或類別的元素可以具有指定的時間屬性,並覆寫在頂層動畫中定義的變數值。

<body>
  <h1>Hello World!</h1>
  <h1>Hello World!</h1>
  <h1 id="helloMe">Hello World!</h1>
  <h1>Hello World!</h1>
  <amp-animation layout="nodisplay" id="animateThis">
    <script type="application/json">
      {
        "selector": "h1",
        "duration": "3s",
        "fill": "both",
        "keyframes": [
          {"transform": "translateX(0px)"},
          {"transform": "translateX(50%)"}
        ],
        "subtargets": [
          {
            "index": 1,
            "duration": "1s"
          },
          {
            "selector": "#helloMe",
            "direction": "reverse",
            "duration": "5s"
          }
        ]
      }
    </script>
  </amp-animation>
  <button on="tap:animateThis.start">start</button>
</body>
在 Playground 中開啟此程式碼片段

串聯動畫

多個動畫可以連接在一起以形成大型序列。您可以透過在 amp-animation 元件內的 animations 陣列中編寫動畫來建立定時效果,例如影片上的疊加層。

<amp-animation id="overlaysAnim" layout="nodisplay">
  <script type="application/json">
    {
      "duration": "3s",
      "fill": "both",
      "animations": [{
          "selector": ".one",
          "keyframes": [{
              "opacity": "1",
              "offset": 0
            },
            {
              "opacity": "1",
              "offset": 0.04
            },
            {
              "opacity": "0",
              "offset": 0.0401
            },
            {
              "opacity": "0",
              "offset": 1
            }
          ]
        },
      ]
    }
  </script>
</amp-animation>

此設定會依序播放每個動畫 3 秒。

對於較大的動畫,animations 陣列內的動畫能夠參考其他 amp-animation 元件。

<amp-animation id="addEnergy" layout="nodisplay">
  <script type="application/json">
  {
    "duration": "0.3s",
    "fill": "both",
    "direction": "alternate",
    "animations": [
      {
        "selector": "#energy",
        "keyframes": [
          {"transform": "scaleX(calc(num(width('#energy'))/10))"},
          {"transform": "scaleX(calc(num(width('#energy'))/10 + 3))"}
        ]
      },
      {
        "animation": "atomExcite"
      }
    ]
  }
  </script>
</amp-animation>
<amp-animation id="atomExcite" layout="nodisplay" trigger="visibility">
<script type="application/json">
  {
    "duration": "0.3s",
    "iterations": "2",
    "fill": "both",
    "direction": "alternate",
    "animations": [
      {
        "selector": ".atom",
        "keyframes": {
          "transform": "translate(20vw)"
        }
      }
    ]
  }
  </script>
</amp-animation>

為未知數量的元素製作動畫

透過使用 [`var(/content/amp-dev/documentation/components/reference/amp-animation.md#css-extensions), 您可以編寫複雜且定時的動畫,這些動畫適用於任何數量的元素。這樣可以輕鬆流暢地為動態和使用者產生的資料製作動畫。

<head>
  <script
    async
    custom-element="amp-animation"
    src="https://cdn.ampproject.org/v0/amp-animation-0.1.js"
  ></script>
  <style amp-custom>
    .parent {
      perspective: 1000px;
      transform-style: preserve-3d;
      position: relative;
      margin: 10px;
      width: 239px;
      height: 335px;
    }
    .card {
      transform-origin: left;
      height: 50%;
      width: 50%;
    }
  </style>
</head>
<body>
  <amp-animation layout="nodisplay" id="cardAdmin">
    <script type="application/json">
      {
        "selector": ".card",
        "--duration": "2s",
        "duration": "var(--duration)",
        "delay": "calc((length() - index() - 1) * var(--duration))",
        "easing": "ease-in",
        "iterations": "1",
        "fill": "both",
        "keyframes": [
          {"transform": "translate3d(0px, 0px, 0px)"},
          {"transform": "translate3d(50%, 0px, 100px)"},
          {"transform": "translate3d(110%, 0px, 0px) rotateY(-20deg)"},
          {"transform": "translate3d(50%, 0px, -100px)"},
          {"transform": "translate3d(0px, 0px, -1px)"}
        ]
      }
    </script>
  </amp-animation>
  <div class="parent" on="tap:cardAdmin.start" tabindex="none" role="animation">
    <amp-img
      class="card"
      src="https://upload.wikimedia.org/wikipedia/commons/7/70/3C.svg"
      layout="fill"
    ></amp-img>
    <amp-img
      class="card"
      src="https://upload.wikimedia.org/wikipedia/commons/3/3a/3H.svg"
      layout="fill"
    ></amp-img>
    <amp-img
      class="card"
      src="https://upload.wikimedia.org/wikipedia/commons/e/e1/KC.svg"
      layout="fill"
    ></amp-img>
  </div>
</body>
在 Playground 中開啟此程式碼片段

此範例的運作方式如下

  • 宣告變數 --duration,並將其值設為兩秒。
  • duration (持續時間) 設定為變數 --duration 的值。
  • 計算套用至每個具有類別 .card 的元素的延遲。 1. [length(/content/amp-dev/documentation/components/reference/amp-animation.md#css-length()-extension) 計算選取了多少.card元素 1. 然後長度減去每個.card的 [index(/content/amp-dev/documentation/components/reference/amp-animation.md#css-index()-extension) 1. 將結果值乘以變數--duration` 1. 最後總計以秒為單位套用至該元素的延遲
  • 動畫會個別套用至每個元素,以便卡片依序洗牌,而不是同時洗牌。

在 AMP Playground 中開啟動畫,並新增更多 amp-img 元素來測試此行為。

在任何地方都看起來很棒

動畫可以包含 conditions (條件)

<head>
  <style amp-custom>
    .drop {
      width: 20px;
      height: 20px;
      background: blue;
      margin-top: 1em;
      border-radius: 50%;
    }
    .right {
      position: absolute;
      right: 0;
      background: red;
    }
  </style>
  <script
    async
    custom-element="amp-animation"
    src="https://cdn.ampproject.org/v0/amp-animation-0.1.js"
  ></script>
</head>
<body>
  <amp-animation id="mediaAnimation" layout="nodisplay">
    <script type="application/json">
      {
        "duration": "1s",
        "iterations": "4",
        "fill": "both",
        "direction": "alternate",
        "animations": [
          {
            "media": "(min-width: 300px)",
            "selector": ".drop",
            "keyframes": {
              "transform": "translate(100vw)"
            }
          },
          {
            "media": "(max-width: 300px)",
            "selector": ".drop",
            "keyframes": {
              "transform": "translate(50vw)"
            }
          },
          {
            "media": "(min-width: 300px)",
            "selector": ".right",
            "keyframes": {
              "transform": "translate(-100vw)"
            }
          },
          {
            "media": "(max-width: 300px)",
            "selector": ".right",
            "keyframes": {
              "transform": "translate(-50vw)"
            }
          }
        ]
      }
    </script>
  </amp-animation>

  <div class="rain">
    <div class="drop"></div>
    <div class="drop right"></div>
    <div class="drop"></div>
    <div class="drop right"></div>
    <div class="drop"></div>
    <div class="drop right"></div>
    <div class="drop"></div>
    <div class="drop right"></div>
  </div>
  <button on="tap:mediaAnimation.start">Start</button>
</body>
在 Playground 中開啟此程式碼片段