AMP

amp-animation

Description

定义和显示动画。

 

Required Scripts

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

Supported Layouts

定义和运行动画。

必需的脚本 <script async custom-element="amp-animation" src="https://cdn.ampproject.org/v0/amp-animation-0.1.js"></script>
支持的布局 nodisplay
示例 animations.amp.html

概述

AMP 动画依赖 Web Animations API 在 AMP 文档中定义和运行动画。

格式

amp-animation 元素会将此类动画定义为 JSON 结构。

顶层动画规范

顶层对象用于定义整个动画过程,其中包含任意数量的动画组件(定义为 animations 数组):

<amp-animation layout="nodisplay">
<script type="application/json">
{
  // Timing properties
  ...
  "animations": [
    {
      // Animation 1
    },
    ...
    {
      // Animation N
    }
  ]
}
</script>
</amp-animation>

在 DOM 中的位置

仅当 trigger="visibility" 时,才允许将 <amp-animation> 作为 <body> 元素的直接子级。如果未指定 trigger 且动画播放通过其操作以编程方式控制,则该元素可以放置在 DOM 中的任意位置。

动画组件

每个动画组件都是一种关键帧效果,并且包含以下各项:

  • 选择器引用的目标元素
  • 条件:媒体查询和支持条件
  • 时间属性
  • 关键帧
{
  "selector": "#target-id",
  // Conditions
  // Variables
  // Timing properties
  // Subtargets
  ...
  "keyframes": []
}

条件

条件可用于指定相应动画组件是否包含在最终动画中。

媒体查询

可以使用 media 属性指定媒体查询。该属性可以包含 Window.matchMedia API 允许的任何表达式,并且对应于 @media CSS 规则。

如果已为某动画组件指定值,则仅当媒体查询与当前环境匹配时,该动画组件才会包含在最终动画中。

支持条件

可以使用 supports 属性指定支持条件。该属性可以包含 CSS.supports API 允许的任何表达式,并且对应于 @supports CSS 规则。

如果已为某动画组件指定值,则仅当支持条件与当前环境匹配时,该动画组件才会包含在最终动画中。

动画 switch 语句

在有些情况下,可以非常方便地将多个具有可选默认值的条件动画合并成单个动画,只需按以下格式使用 switch 动画语句即可完成此操作:

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

switch 动画中,系统会按照指定的顺序评估候选项,然后执行第一个与条件语句匹配的动画,并忽略其余动画。

例如,以下动画会运行运动路径动画(如果受支持),然后回退到转换操作:

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

变量

动画组件可以通过 var() 表达式声明将用于时间值和关键帧值的 CSS 变量。系统会根据当前目标上下文对 var() 表达式进行求值。在动画组件中指定的 CSS 变量会传播到嵌套动画,应用于动画目标,然后替换最终动画中使用的 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 会传播到嵌套动画,但会被 #target1 动画替换,并在稍后用于 transform 属性。
  • --y 未在 <amp-animation> 中指定,因此系统将在 #target1 元素中查询该值。如果在 CSS 中未指定该值,则该值会默认为 0px

如需详细了解 var(),请参阅var()calc()”部分

时间属性

顶层动画和动画组件可以包含时间属性。网页动画规范的 AnimationEffectTimingProperties 中对这些属性进行了详细定义。允许的一组属性包括:

属性 类型 默认值 说明
duration 时间 0 动画时长。可以是数值(以毫秒为单位),也可以是 CSS 时间值(例如 `2s`)。
delay 时间 0 动画开始执行前的延迟时间。可以是数值(以毫秒为单位),也可以是 CSS 时间值(例如 `2s`)。
endDelay 时间 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 值。例如,可以将“duration”指定为 10001s1000ms。此外,这些属性还允许使用 calc()var() 以及其他 CSS 表达式。

采用 JSON 格式的时间属性示例:

{
  ...
  "duration": "1s",
  "delay": 100,
  "endDelay": "var(--end-delay, 10ms)",
  "easing": "ease-in",
  "fill": "both"
  ...
}

动画组件会继承为顶层动画指定的时间属性。

子目标

在任何可以指定 selector 的位置,都可以指定 subtargets: []。子目标可以替换动画中为特定子目标(通过索引或 CSS 选择器指明)指定的时间属性或变量。

例如:

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

在此示例中,默认情况下,与“.target”匹配的所有目标都会有 100 毫秒的延迟,且“--y”为 100 像素。不过,第一个目标 (index: 0) 的延迟时间会被替换为 200 毫秒;奇数目标的“--y”会被替换为 200 像素。

请注意,可以有多个子目标与同一个目标元素匹配。

关键帧

要指定关键帧,可以采用网页动画规范的“关键帧”部分介绍的多种方式,也可以采用字符串形式(引用 CSS 中的 @keyframes 名称)。

下面列举了一些典型的关键帧定义。

采用简写对象形式“到”格式指定 100% 处的最终状态:

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

采用简写对象形式“从-到”格式指定 0% 处的起始状态以及 100% 处的最终状态:

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

采用简写对象形式“值-数组”格式指定起始状态、最终状态以及多个(等间距)偏移处的多个值:

{
  "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)"}
]
}

如需了解其他关键帧格式,请参阅网页动画规范

这些属性值可以是任何有效的 CSS 值,包括 calc()var() 以及其他 CSS 表达式。

通过 CSS 指定关键帧

另一种指定关键帧的方式是在文档的样式表(<style> 标记)中以 @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 基本相当于 JSON 中的内嵌关键帧定义。不过,这两者之间存在一些细微差别:

  • 为了获得广泛的平台支持,可能需要添加供应商前缀(如 @-ms-keyframes {}-moz-transform)。如果采用 JSON 格式,则不需要也不允许添加供应商前缀,但如果采用 CSS 格式,则可能必须要添加。
  • 以 CSS 格式指定关键帧时,不支持 calc()var() 的平台将无法使用 amp-animation polyfill。因此,建议您始终在 CSS 中添加后备值。
  • CSS 中无法使用 width()height()num()rand()index()length() 等 CSS 扩展。

列入白名单的关键帧属性

并非所有 CSS 属性都可用于关键帧。只有新型浏览器可以优化和快速以动画形式呈现的 CSS 属性才可列入白名单。随着越来越多的属性被确认为可提供良好性能,此名单将不断扩充。目前,该名单包含以下属性: - opacity - transform - visibility - offset-distance

请注意,不需要也不允许使用带供应商前缀的 CSS 属性。

动画配置的缩略形式

如果动画仅涉及一个元素且一个关键帧效果就已足够,则配置可以缩减为只有这一个动画组件。例如:

<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": ".target-class",
    "duration": 1000,
    "keyframes": {"opacity": 1}
  },
  {
    "selector": ".target-class",
    "duration": 600,
    "delay": 400,
    "keyframes": {"transform": "scale(2)"}
  }
]
</script>
</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>

在此示例中,无论“target-class”是与零个、一个还是多个元素匹配,系统都会为每个匹配的目标执行“anim2”。

在调用方动画中指定的变量和时间属性也会传递到所添加的动画中。

var()calc() 表达式

amp-animation 允许将 var()calc() 表达式用于时间值和关键帧值。

例如:

<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>

系统会在不直接支持 var()calc() 的平台上对其执行 polyfill 操作,还会从相应目标元素提取 var() 属性。但遗憾的是,系统无法完全对 var() 执行 polyfill 操作。因此,如果兼容性很重要,强烈建议在 var() 表达式中添加默认值。例如:

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

动画组件可以将自己的变量指定为 --var-name 字段。这些变量会传播到嵌套动画中,并替换通过样式表(<style> 标记)指定的目标元素的变量。var() 表达式会先尝试解析在动画中指定的变量值,然后通过查询目标样式进行解析。

CSS 扩展

amp-animation 提供了一些 CSS 扩展,以满足典型动画需求:rand()num()width()height()。CSS 值(包括时间值和关键帧值)能在 amp-animation 中的哪些位置使用,这些函数就能在哪些位置使用。

CSS index() 扩展

index() 函数可返回动画效果中当前目标元素的索引。当多个目标使用 selector 属性呈现相同的动画效果时,此函数的用处最大。第一个与选择器匹配的目标的索引为 0,第二个目标的索引为 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() 扩展

width()height() 扩展可返回动画元素或通过选择器指定的元素的宽度/高度。返回的值以像素为单位,例如 100px

支持的形式如下:

  • width()height() - 动画元素的宽度/高度。
  • width('.selector')height('.selector') - 通过选择器指定的元素的宽度/高度。您可以使用任何 CSS 选择器,例如 width('#container &gt; li')
  • width(closest('.selector'))height(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)"
  }

SVG 动画

SVG 非常棒,我们建议将其用于动画!

SVG 动画受到列入白名单的关键帧属性中所述的那些 CSS 属性的支持,但存在一些细微差别:

  • IE/Edge SVG 元素不支持 CSS transform 属性transform 动画本身已执行过 polyfill 操作。不过,不会应用在样式表中指定的初始状态。如果初始转换状态在 IE/Edge 上很重要,建议您通过 SVG transform 属性进行复制。
  • 虽然已针对 IE/Edge 对 transform CSS 执行 polyfill 操作,但遗憾的是,无法对 transform-origin 执行 polyfill 操作。因此,如果需要与 IE/Edge 兼容,建议仅使用默认 transform-origin
  • 大多数浏览器目前都无法正确解读 transform-origin CSS。请参阅 ChromeSafariFirefox 的相关问题。实现 CSS transform-box 后,大部分引起混淆的问题应该会得到解决。如果 transform-origin 至关重要,建议您同时添加必需的 transform-box CSS,以确保未来的兼容性。

触发动画

您可以通过 trigger 属性或 on 操作触发动画。

trigger 属性

对于 trigger 属性,目前 visibility 是唯一可用的值。visibility 会在基础文档或嵌入内容可见时(位于视口中时)触发。

例如:

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

通过 on 操作触发

例如:

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

on 操作

amp-animation 元素会导出以下操作:

  • start - 启动尚未运行的动画。时间属性和变量可指定为操作参数,如 anim1.start(delay=-100, --scale=2)
  • restart - 启动动画或重新启动当前正在运行的动画。时间属性和变量可指定为操作参数,如 anim1.start(delay=-100, --scale=2)
  • pause - 暂停当前正在运行的动画。
  • resume - 继续当前正在运行的动画。
  • togglePause - 在暂停/继续操作之间切换。
  • seekTo - 暂停动画,并跳转到通过 time 参数(以毫秒为单位)或 percent 参数(作为时间轴中的百分比点)指定的时间点。
  • reverse - 反向运行动画。
  • finish - 结束动画。
  • cancel - 取消动画。
需要更多帮助?

您已多次阅读本文档,但它仍未能涵盖您的所有问题?也许其他人也这么觉得:在 Stack Overflow 上与他们联系。

前往 Stack Overflow
发现错误或缺少功能?

AMP 项目强烈鼓励您参与并做出贡献!我们希望您能成为我们开放源代码社区的持续参与者,但我们也欢迎您对所热衷问题做出一次性贡献。

前往 GitHub