滚动链接动画通常可以为网站增添一抹档次,但长期以来一直是 JavaScript 的专利。现在,一个全新的规范正在实施,使我们能够使用 CSS 创建丰富的滚动驱动体验!
当我们想到滚动驱动的动画时,我们通常指以下两件事之一:
-
当用户滚动时发生的动画,动画的进度显式链接到滚动进度。例如,长文章的进度条。
-
当元素进入、退出或穿过可见区域(通常是视口)时在元素上发生的动画,但它可能是另一个可滚动容器的可见部分(这被定义为滚动端口)。
滚动驱动动画规范涵盖了这两种类型的动画。在本文中,我们将首先了解滚动进度时间轴,顾名思义,它将动画链接到滚动进度。
使用动画时间轴 {#using_the_animation_timeline}
在此示例中,我们将实现一个常见功能:当用户滚动网页时,将简单的进度条动画化以从左向右缩放。因为我们想要将动画链接到根滚动条的进度,所以我们可以使用匿名滚动进度时间轴。
首先让我们定义动画本身。我们希望进度条从左向右缩放,因此我们将使用转换:
@keyframes scaleProgress {
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
为了将进度条元素的动画与滚动进度相关联,我们使用了该animation-timeline
属性并将scroll()
函数设置为其值。
.progress {
animation-timeline: scroll();
animation: scaleProgress auto linear;
}
该scroll()
函数允许我们指定滚动容器和轴。默认值为scroll(nearest block)
,这意味着动画将链接到块轴上最近的可滚动祖先。这对于我们的目的来说已经足够了,尽管我们可以选择将根指定为滚动容器,因为我们希望将动画显式链接到视口滚动的进度。
.progress {
animation-timeline: scroll(root block);
}
最后,我们需要将动画添加到进度条元素,并将关键帧动画作为animation-name
. 我们需要将动画持续时间设置为auto
,因为持续时间将由滚动进度决定。我们还设置了缓动 ( animation-timing-function
),linear
以便它能够与滚动顺利进行。如果我们使用默认值 ( ease
),动画将缓慢开始,然后快速加速,然后在最后减速 - 这不是我们想要的进度指示器!
.progress {
animation-timeline: scroll(root);
animation-name: scaleProgress;
animation-duration: auto;
animation-timing-function: linear;
}
我们可以使用简写属性来压缩它animation
:
.progress {
animation-timeline: scroll(root);
animation: scaleProgress auto linear;
}
多种动画 {#multiple_animations}
就像常规关键帧动画一样,我们可以同时应用多个滚动时间轴动画,例如更改进度条的颜色。
.progress {
animation: scaleProgress auto linear, colorChange auto linear;
animation-timeline: scroll(root);
}
@keyframes scaleProgress {
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
@keyframes colorChange {
0% {
background-color: red;
}
50% {
background-color: yellow;
}
100% {
background-color: lime;
}
}
重复和反转动画 {#repeating_and_reversing_animations}
animation-direction
滚动进度动画可以与现有的和属性结合使用animation-iteration-count
。因此,我们可以使动画在整个滚动时间轴中重复多次,或者反向播放。当我们滚动时,"球"会弹跳几次。
.progress {
animation: bounce auto linear 6 alternate;
animation-timeline: scroll(root);
}
@keyframes bounce {
100% {
transform: translateY(-50vh);
}
}
定位非祖先滚动容器 {#targeting_a_non-ancestor_scroll_container}
有时,我们可能想要为不是滚动容器后代的元素设置动画,但仍将该元素的动画链接到滚动容器的进度。为此,我们需要创建一个命名的滚动进度时间轴。我们将使用简写属性(和 的scroll-timeline
简写)在滚动容器上声明时间轴的名称和轴。同样,块轴是默认值。时间线名称必须以两个破折号作为前缀(类似于自定义属性),这可确保它不会与其他属性值冲突。scroll-timeline-name``scroll-timeline-axis
滚动容器必须是具有滚动能力的元素。
.scroller {
max-height: 300px;
overflow: scroll;
scroll-timeline: --scale-progress block;
}
我们可以使用该属性将要设置动画的元素链接到滚动时间轴animation-timeline
。
/* Sibling of .scroller */
.progress {
animation: scaleProgress auto linear;
animation-timeline: --scale-progress;
}
@keyframes scaleProgress {
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
对滚动容器的祖先进行动画处理 {#animating_an_ancestor_of_a_scroll_container}
如果我们想要设置动画的元素是滚动容器的同级元素,则此操作有效。如果我们想要为祖先或兄弟姐妹的后代制作动画怎么办?
我们还需要一个 CSS 属性 ,timeline-scope
它允许我们修改命名时间线的范围以包含设置它的元素。body
例如,如果我们在 上设置此属性,我们现在可以为该元素的背景颜色设置动画,尽管它是滚动容器的祖先。
我们看一下代码:
/* Ancestor element: We want to scope the scroll timeline to include this element and its descendants */
body {
timeline-scope: --scale-progress;
/* Apply the animation */
animation: colorChange auto linear forwards;
animation-timeline: --scale-progress;
}
/* The scroll container on which we declare our timeline */
.scroller {
max-height: 300px;
overflow: scroll;
scroll-timeline: --scale-progress block;
}
/* Apply the animation on the sibling as before */
.progress {
animation: scaleProgress auto linear;
animation-timeline: --scale-progress;
}
注意: timeline-scope
目前仅在启用了实验性网络平台功能的 Chrome Canary 和 Chrome 116 中受支持。
探索创意示例 {#exploring_creative_examples}
到目前为止,我们已经创建了一些相当基本的进度条动画 - 也许是滚动进度时间线更明显的用例之一。但没有什么可以阻止我们用滚动动画发挥创意。
水平图像滚动条 {#horizontal_image_scroller}
当用户垂直滚动时对元素进行水平动画可以使网页感觉更加动态且更少线性。在这里,我们对一行图像进行动画处理,以便当用户垂直滚动时它们从左侧滑入。
使用运动路径 {#using_a_motion_path}
我们可以沿着 CSS 中的路径定位元素并为其设置动画,用于offset-path
定义元素要遵循的运动路径。这是比矩形进度条更有趣的指示进度的方式!
组合多个动画 {#combining_multiple_animations}
在此演示中,我们在滚动时对多个元素进行动画处理:显示文本,同时框从左向右滑动和翻筋斗。为了简化代码并避免创建多个关键帧,我们对自定义属性进行动画处理并translateY
使用三角函数计算值,所有主要浏览器的最新版本都支持三角函数。与转换属性不同,自定义属性在主线程上进行动画处理,这意味着如果您想对大量自定义属性进行动画处理,您的网站可能会遇到性能不佳的问题。
请参阅 CodePen 上的完整示例
辅助功能和用户动作偏好 {#accessibility_and_users_motion_preferences}
与任何侵入性动画一样,我们应该始终优先考虑可访问性,并确保为那些不想使用动画的人关闭动画。这对于滚动驱动的动画尤其重要,即使对于通常不患有前庭疾病的用户来说,这也会导致晕动病的感觉。如果您想了解更多信息,请查看尊重用户的动作偏好,了解如何使用prefers-reduced-motion
媒体查询来确保您的动画可访问。
概括 {#summary}
那么,CSS 中的滚动时间线动画与 JS 库相比如何(一旦它们得到普遍支持)?如果您要创建特别复杂的动画,您可能仍然需要使用像 的库GSAP
,它特别适合处理复杂的编排。库还可以为我们提供自定义缓动和 GSAP 的 Inertia 插件(它允许动画在滚动完成后滑行到停止,而不是突然停止)等功能。目前,我们没有办法在 CSS 中检测元素当前是否正在滚动。
同样,如果您的动画对于用户体验至关重要,您可能需要暂时推迟,因为滚动链接动画可能需要一段时间才能得到普遍支持。
另一方面,如果您需要一些相对简单的滚动驱动动画,CSS 可以为您(和您的用户)节省大量 JS 负载,从而为您带来巨大的性能优势!