滚动绑定效果基础
简介
amp-position-observer 与 amp-animation 结合使用是一种强大的构建模块,可以处理各种用例,例如滚动绑定动画、视差效果以及元素进入和退出视口时的过渡。
在本教程中,我们将详细介绍其中一些用例。
设置
amp-position-observer 是一个功能性组件,它会监视用户滚动时元素在视口中的位置,并派发 enter
、exit
和 scroll:<视口中位置的百分比>
事件。
这些事件反过来可以用于 play
、pause
或 seek
由 amp-animation 定义的动画时间线,以创建滚动绑定和基于可见性的效果。
<script async custom-element="amp-position-observer" src="https://cdn.ampproject.org/v0/amp-position-observer-0.1.js"></script>
amp-animation 是一个 UI 组件,它依赖于 Web Animations API 来定义和运行 AMP 文档中的关键帧动画。
<script async custom-element="amp-animation" src="https://cdn.ampproject.org/v0/amp-animation-0.1.js"></script>
样式
此处包含这些示例使用的 CSS,以供参考。
这些规则只是为了使示例能够工作,而不是这里涵盖的概念的基础。
<style amp-custom>
/*
* Fidget Spinner styles
*/
.fidget-spinner-scene {
margin: 10px 20%;
}
/*
* Card transition styles
*/
.card {
margin: 10%;
position: relative;
}
.card-title {
padding: 5%;
padding-right: 40%;
font-size: 50%;
font-weight: bold;
color: #FAFAFA;
transform: translateX(-100%);
}
/*
* Parallax window styles
*/
.parallax-image-window {
overflow: hidden;
}
.parallax-image-window amp-img {
margin-bottom: -30%;
}
/*
* Carousel transition styles
*/
.carousel-component {
margin-right: -60%;
margin-left: 60%;
}
.carousel-parent {
overflow: hidden;
}
</style>
滚动绑定动画
让我们创建一个随着用户滚动页面而旋转的指尖陀螺。
此示例展示了组合 amp-position-observer
和 amp-animation
背后的核心概念:当元素通过滚动在视口中移动时,能够推进关键帧动画时间线。
我们的指尖陀螺场景是一个带有 image
的 div
。我们在场景中添加一个 amp-position-observer
元素作为子元素,以监视其在视口中的进度。让我们看看细节
on:scroll
:当用户滚动时场景的位置发生变化时,位置观察器会触发此事件。该事件提供一个百分比值(介于 0 和 1 之间的十进制数),表示场景在视口中的起始位置和结束位置之间的进度。spinAnimation.seekTo(percent=event.percent)
:我们将在下一步定义一个amp-animation
来执行旋转,这里我们通过在发生scroll
事件时触发动画上的seekTo
操作来耦合amp-position-observer
和amp-animation
。这就是我们如何指定希望通过滚动使场景在视口中移动时推进动画时间线。intersection-ratios
:定义在amp-position-observer
触发其任何事件之前,场景在视口中应该可见多少。在这里,我们希望仅在指尖陀螺完全可见时才发生旋转,因此我们将其设置为1
。

<div class="fidget-spinner-scene">
<amp-position-observer on="scroll:spinAnimation.seekTo(percent=event.percent)" intersection-ratios="1" layout="nodisplay">
</amp-position-observer>
<amp-img id="fidgetSpinnerImage" width="1024" height="1114" layout="responsive" src="/static/samples/img/fidget.png" alt="Picture of a fidget spinner"></amp-img>
</div>
现在我们需要定义动画本身
在这种情况下相当简单,我们希望 fidgetSpinnerImage
旋转 360 度,因此我们只需将 "transform": "rotate(360deg)"
定义为最后一个(也是唯一的)关键帧。让我们看看细节
id="spinAnimation"
:我们需要为动画赋予一个 Id,以便我们可以从位置观察器引用它。"duration": "1"
:在这种情况下,duration
的值无关紧要,因为我们通过滚动推进时间线,所以我们将其设置为1
"direction": "reverse"
:由于 iOS 中存在 Web Animations 的错误,因此需要这样做。"animations"
:在这里我们可以定义一个或多个基于关键帧的动画。在我们的例子中,我们只需要一个。"selector"
:"#fidgetSpinnerImage"
是将指尖陀螺作为动画目标的 selector。"keyframes":
我们将"transform": "rotate(360deg)"
定义为最后一个(也是唯一的)关键帧。请注意,如果未提供,amp-animation
会自动填充第一个关键帧。
amp-animation
具有许多其他功能,请参阅 API 参考以了解有关 amp-animations
的更多信息。
<amp-animation id="spinAnimation" layout="nodisplay">
<script type="application/json">
{
"duration": "1",
"fill": "both",
"direction": "reverse",
"animations": [
{
"selector": "#fidgetSpinnerImage",
"keyframes": [
{ "transform": "rotate(360deg)" }
]
}
]
}
</script>
</amp-animation>
淡入淡出和滑动过渡
现在我们已经了解了 amp-position-observer
和 amp-animation
背后的基本核心概念,让我们深入研究它们可以组合以创建有趣过渡的更多创造性方法。
在此示例中,我们将时间绑定过渡和滚动绑定过渡组合在一起,以创建一种效果,其中卡片的透明度与卡片在视口中可见的程度(滚动绑定)相关联,并且当卡片进入和退出视口时,卡片的标题会动画显示/隐藏(时间绑定)。
我们的卡片场景仅由一个图像和一个叠加的标题组成。在这里,我们定义了两个具有不同 intersection-ratios
值的位置观察器
- 第一个位置观察器将控制用户滚动时图像的透明度。
- 第二个位置观察器将在场景大部分可见 (80%) 时为标题运行一个时间绑定的滑动动画,并在场景稍微退出视口 (20%) 时再次“反向”运行它。
<div class="card ampstart-card">
<amp-position-observer on="scroll:fadeTransition.seekTo(percent=event.percent)" intersection-ratios="0" layout="nodisplay">
</amp-position-observer>
<amp-position-observer on="enter:slideTransition.start; exit:slideTransition.start,slideTransition.reverse" intersection-ratios="0.8" layout="nodisplay">
</amp-position-observer>
<amp-fit-text layout="fill">
<div class="card-title">
Organic, fresh tomatoes and pasta!
</div>
</amp-fit-text>
<amp-img id="cardImage" width="1280" height="898" layout="responsive" src="/static/samples/img/food.jpg" alt="Picture of food table."></amp-img>
</div>
让我们定义滚动绑定淡入/淡出过渡的关键帧。
我们以一种使图像在时间线的前 40% 内获得完全不透明度并在时间线的最后 40% 内开始淡出的方式定位 #cardImage
并定义关键帧。
请注意,由于控制此动画的位置观察器将 intersection-ratios
设置为 0
,因此当用户滚动 ViewportHeight + 2 * SceneHeight
像素时,我们将遍历整个时间线。
<amp-animation id="fadeTransition" layout="nodisplay">
<script type="application/json">
{
"duration": "1",
"fill": "both",
"direction": "reverse",
"animations": [
{
"selector": "#cardImage",
"keyframes": [
{ "opacity": "0.3", "offset": 0 },
{ "opacity": "1", "offset": 0.4 },
{ "opacity": "1", "offset": 0.6 },
{ "opacity": "0.3", "offset": 1 }
]
}
]
}
</script>
</amp-animation>
对于标题的滑入/滑出效果,我们只需定义一个 500 毫秒的动画,该动画将沿 X 轴移动标题。
当场景大部分可见/不可见时,此动画将仅通过第二个位置观察器(以正常或反向方向)触发。
<amp-animation id="slideTransition" layout="nodisplay">
<script type="application/json">
{
"duration": "500ms",
"fill": "both",
"easing": "ease-out",
"iterations": "1",
"animations": [
{
"selector": ".card-title",
"keyframes": [
{ "transform": "translateX(-100%)" },
{ "transform": "translateX(0)" }
]
}
]
}
</script>
</amp-animation>
视差图像窗口
视差是可以通过组合 amp-animation
和 amp-position-observer
实现的另一种效果。
视差通常涉及在用户滚动时沿 Y 轴平移元素。
在这里,我们定义了一个场景,该场景的高度小于其内部的图像,当用户滚动时,我们会移动图像,从而在图像中创建一个视差窗口。
<div class="parallax-image-window">
<amp-position-observer on="scroll:parallaxTransition.seekTo(percent=event.percent)" intersection-ratios="0" layout="nodisplay">
</amp-position-observer>
<amp-img id="parallaxImage" width="1280" height="873" layout="responsive" src="/static/samples/img/elephant.jpg" alt="Picture of an elephant"></amp-img>
</div>
动画本身只是通过 "transform": "translateY(-30%)"
向上移动图像
<amp-animation id="parallaxTransition" layout="nodisplay">
<script type="application/json">
{
"duration": "1",
"fill": "both",
"direction": "reverse",
"animations": [
{
"selector": "#parallaxImage",
"keyframes": [
{ "transform": "translateY(-30%)" }
]
}
]
}
</script>
</amp-animation>
轮播过渡
我们还可以将这些效果与其他 AMP 组件(如 amp-carousel
)一起使用。
在此示例中,我们有一个轮播,其中第一个项目被推到右侧,当轮播变得可见时,它会弹回原位,从而提供轮播可以在水平方向上滚动的视觉“提示”。
<div class="carousel-parent">
<amp-carousel class="carousel-component" height="300" layout="fixed-height" type="carousel">
<amp-position-observer on="enter:carouselTransition.start" intersection-ratios="0.8" layout="nodisplay">
</amp-position-observer>
<amp-img src="https://unsplash.it/800/600?image=1003" width="400" height="300" alt="a sample image"></amp-img>
<amp-img src="https://unsplash.it/800/600?image=1043" width="400" height="300" alt="another sample image"></amp-img>
<amp-img src="https://unsplash.it/800/600?image=1032" width="400" height="300" alt="and another sample image"></amp-img>
</amp-carousel>
</div>
在这里,我们定义了一个延迟 200 毫秒的时间绑定动画,该动画将在 500 毫秒内将轮播滑动到左侧。
此动画将仅由位置观察器触发一次,如上所述。
<amp-animation id="carouselTransition" layout="nodisplay">
<script type="application/json">
{
"duration": "500ms",
"fill": "both",
"easing": "ease-in",
"delay": "200ms",
"animations": [
{
"selector": ".carousel-component",
"keyframes": [
{ "transform": "translateX(-60%)" }
]
}
]
}
</script>
</amp-animation>
如果此页面上的解释没有涵盖您的所有问题,请随时联系其他 AMP 用户讨论您的确切用例。
转到 Stack Overflow 一个无法解释的功能?AMP 项目强烈鼓励您的参与和贡献!我们希望您成为我们开源社区的持续参与者,但我们也欢迎您针对您特别感兴趣的问题做出一次性贡献。
在 GitHub 上编辑示例-
由 @aghassemi 撰写