AMP

复杂动画简介

对于无法通过添加和移除类来驱动的动画,AMP 提供了几个特定于动画的组件。这些组件将 AMP 的原则应用于动画:它们快速、高效且以用户为先。AMP 限制了关键帧内允许的 CSS 属性,但提供了诸如精细控制、无缝动画和跨浏览器兼容性等好处,而无需额外的工作。

如果你需要严格控制播放,以及同时让多个元素以精确的时间进行动画,请使用 amp-animation。

创建基本的 AMP 动画

amp-animation 组件允许在 AMP 中使用 Web 动画 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 确保对单个元素进行动画处理。

时序属性

时序属性 控制动画的持续时间、播放次数以及关键帧执行的方向。

不需要任何时序属性,但如果缺少与时间和显示相关的属性(例如 durationfill),动画可能无法运行。

关键帧

虽然 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>
在游乐场中打开此代码段

链式动画

多个动画可以连接在一起,形成一个大型序列。你可以通过在 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>
在游乐场中打开此代码段

此示例通过以下方式工作

  • 声明一个变量 --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 游乐场中打开动画,并添加更多 amp-img 元素来测试此行为。

在任何地方看起来都很好

动画可以包括 条件

<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>
在游乐场中打开此代码段