复杂动画入门
重要提示:此文档不适用于您当前选择的格式故事!
对于无法通过添加和删除类驱动的动画,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
中定义。触发器
触发器启动动画序列。当 <body>
在页面上变为可见时,或通过将其连接到 AMP 操作或事件时,amp-animation
扩展程序将启动。
当动画应在页面加载后立即运行(因为它出现在“首屏”或页面的第一个视口中)时,在 <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
,并为其指定值 2 秒。 - 将
duration
设置为变量--duration
的值。 - 计算应用于具有类
.card
的每个元素的延迟。1. [length(/content/amp-dev/documentation/components/reference/amp-animation.md#css-length()-extension)
] 计算选择了多少.card
元素。1. 然后,length 减去每个.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>
-
作者: @CrystalOnScript