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”指定为 1000
、1s
或 1000ms
。此外,这些属性还允许使用 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 > li')
。width(closest('.selector'))
和height(closest('.selector'))
- 通过距离最近的选择器指定的元素的宽度/高度。
width()
和 height()
在实现转换方面尤为有用。left
、top
及类似 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 上很重要,建议您通过 SVGtransform
属性进行复制。 - 虽然已针对 IE/Edge 对
transform
CSS 执行 polyfill 操作,但遗憾的是,无法对transform-origin
执行 polyfill 操作。因此,如果需要与 IE/Edge 兼容,建议仅使用默认transform-origin
。 - 大多数浏览器目前都无法正确解读
transform-origin
CSS。请参阅 Chrome、Safari 和 Firefox 的相关问题。实现 CSStransform-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