滚动链接动画规范 是 CSS 的一项即将推出的实验性功能。得益于 @scroll-timeline
at-rule 和 animation-timeline
属性,该规范提供了通过滚动控制常规 CSS 动画的时间位置的功能。
在这篇文章中,我们将探讨一些滚动链接动画派上用场的实际用例,以及它们如何丰富访客的浏览体验。
👨🔬 本文介绍的 CSS 功能仍处于实验阶段,尚未最终确定。在撰写本文时,除了 Chromium ≥ 89(启用了“实验性 Web 平台功能”标志)外,任何浏览器都不支持这些功能。
CSS 滚动链接动画,快速入门
使用滚动链接动画规范中描述的功能,您可以通过滚动驱动 CSS 动画:当您向下或向上滚动滚动容器时,链接的 CSS 动画将相应地前进或倒退。这些滚动链接动画可以为您的页面添加非常不错的效果。
虽然已经存在几个用于实现这些滚动链接动画的 JavaScript 库,但滚动链接动画规范与它们的区别在于
- 提供了 JS 和 CSS 接口来实现这些效果
- 保持高性能,因为动画将在合成器上运行(例如,“主线程之外”)
虽然滚动链接动画规范还描述了一个与 Web 动画 API 完美集成的 JavaScript 接口,但本文将仅关注其 CSS 对等项。
要在 CSS 中实现基本的滚动链接动画,您需要三个关键部分
- CSS 动画
- 滚动时间轴
- 两者之间的链接
CSS 动画
这与我们已知的常规 CSS 动画相同
@keyframes adjust-progressbar {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
与往常一样,使用 animation
属性 将其附加到元素。
#progressbar {
animation: 1s linear forwards adjust-progressbar;
}
滚动时间轴
滚动时间轴允许我们将滚动距离映射到动画进度。在 CSS 中,我们使用 CSS @scroll-timeline
at-rule 来描述这一点。
@scroll-timeline scroll-in-document-timeline {
source: auto;
orientation: vertical;
scroll-offsets: 0%, 100%;
}
除了为滚动时间轴命名外,还可以使用多个描述符进行配置
source
描述触发时间轴激活并驱动时间轴进度的可滚动元素。默认情况下,它是整个文档(值:auto
)orientation
确定应触发动画的滚动方向。默认情况下,它是vertical
。scroll-offsets
属性是一个关键点数组,描述动画应处于活动状态的范围。这些偏移量可以是相对/绝对值(例如百分比和长度)或基于元素的偏移量。
规范的早期版本要求您还设置 time-range
描述符。该描述符已删除,并将自动接管链接动画的 animation-duration
。您可能仍然可以在演示中看到该描述符的痕迹,但可以安全地忽略它。
两者之间的链接
要将我们的 @scroll-timeline
与我们的 CSS 动画关联,我们使用新的 animation-timeline
CSS 属性,并使其引用时间轴的名称。
#progressbar {
animation: 1s linear forwards adjust-progressbar;
animation-timeline: scroll-in-document-timeline;
}
设置完成后,adjust-progressbar
动画不会在页面加载时自行运行,而只会随着页面的向下滚动而前进。
实际用例
除了上面介绍的进度条演示外,滚动链接动画还有一些其他用例或场景。
- 视差标题
- 图像显示/隐藏
- 打字动画
- 轮播指示器
- 滚动侦测
视差标题
滚动链接动画最经典的用例是视差效果,其中页面的多个部分似乎具有不同的滚动速度。只使用 CSS 就可以创建这种类型的效果,但这需要 使用涉及 translate-z()
和 scale()
的令人眼花缭乱的 transform
技巧。
受到 Firewatch 标题(它使用上述 transform
技巧)的启发,我创建了这个使用 CSS 滚动时间轴的版本
与原始演示相比
- 保留了标记,除了不再需要的
.parallax__cover
。 <body>
被赋予了一个min-height
来创建一些滚动区域。- 调整了
.parallax
元素及其.parallax_layer
子元素的位置。 transform
/perspective
技巧被滚动时间轴替换。
每个不同的图层都使用相同的滚动时间轴:在 100vh
的距离内滚动。
@scroll-timeline scroll-for-100vh {
scroll-offsets: 0, 100vh;
}
.parallax__layer {
animation: 1s parallax linear;
animation-timeline: scroll-for-100vh;
}
图层之间的不同之处在于,随着我们向下滚动,它们移动的距离
- 后面的图层应保持静止,例如,移动
0vh
。 - 最前面的图层应该移动得最快,例如,
100vh
。 - 所有中间的图层都进行插值。
@keyframes parallax {
to {
transform: translateY(var(--offset));
}
}
.parallax__layer__0 {
--offset: 100vh;
}
.parallax__layer__1 {
--offset: 83vh;
}
.parallax__layer__2 {
--offset: 67vh;
}
.parallax__layer__3 {
--offset: 50vh;
}
.parallax__layer__4 {
--offset: 34vh;
}
.parallax__layer__5 {
--offset: 17vh;
}
.parallax__layer__6 {
--offset: 0vh;
}
由于最前面的图层移动的距离更大,因此它们看起来比后面的图层移动得更快,从而实现了视差效果。
图像显示/隐藏
滚动链接动画的另一个很好的用例是图像显示:随着图像滑动进入视野,它将显示出来。
默认情况下,图像的透明度为 0,并使用 clip-path
进行遮罩
#revealing-image {
opacity: 0;
clip-path: inset(45% 20% 45% 20%);
}
在最终状态下,我们希望图像完全可见,因此我们将动画的结束帧设置为反映这一点
@keyframes reveal {
to {
clip-path: inset(0% 0% 0% 0%);
opacity: 1;
}
}
通过使用 基于元素的偏移量 作为滚动时间轴的偏移量,我们可以让显示动画仅在图像本身滑入视野时开始。
@scroll-timeline revealing-image-timeline {
scroll-offsets:
selector(#revealing-image) end 0.5,
selector(#revealing-image) end 1
;
}
#revealing-image {
animation: reveal 1s linear forwards;
animation-timeline: revealing-image-timeline;
}
😵 无法理解这些基于元素的偏移量?此可视化/工具 可以帮助您。
打字动画
由于 CSS 滚动时间轴可以链接到任何现有的 CSS 动画,因此您可以使用任何 CSS 动画演示并对其进行转换。例如,此打字动画
通过添加滚动时间轴和 animation-timeline
属性,它可以调整为“滚动时打字”
请注意,为了创建一些滚动区域,<body>
的高度也设置为 300vh
。
使用不同的动画,上面的代码可以轻松调整以创建滚动时缩放效果
我认为这两种效果非常适合文章开头。
轮播/滑块指示器
轮播(也称为滑块)的组件之一是指示器,它显示轮播包含多少个幻灯片以及当前哪个幻灯片处于活动状态。这通常使用项目符号来完成。
这同样是我们可以使用 CSS 滚动时间线来实现的,如 Fabrizio Calderan 创建的此演示所示
活动状态的项目符号是通过 .slider nav::before
注入的,并设置了使其在其他项目符号上移动的动画
/* Styling of the dots */
.slider nav::before, .slider a {
inline-size: 1rem;
aspect-ratio: 1;
border-radius: 50%;
background: #9bc;
}
/* Positioning of the active dot */
.slider nav::before {
content: "";
position: absolute;
z-index: 1;
display: block;
cursor: not-allowed;
transform: translateX(0);
animation: dot 1s steps(1, end) 0s forwards;
}
/* Position over time of the active dot */
@keyframes dot {
0%
{ transform: translateX(0); }
33%
{ transform: translateX(calc((100% + var(--gap)) * 1)); }
66%
{ transform: translateX(calc((100% + var(--gap)) * 2)); }
100%
{ transform: translateX(calc((100% + var(--gap)) * 3)); }
}
通过将 @scroll-timeline
附加到滑块,指示活动状态的圆点可以在您滚动时移动
@scroll-timeline slide {
source: selector(#s);
orientation: inline;
}
.slider nav::before {
/* etc. */
animation-timeline: slide;
}
由于动画中包含了 steps()
函数,因此圆点只有在幻灯片滑到其位置后才会移动。当您移除它时,您会更清楚地看到圆点是如何随着您的滚动而移动的
💡 这感觉就像 Christian Shaefer 的纯 CSS 轮播 中最后缺失的部分。
滚动侦察
早在 2020 年初,我就创建了 带滚动活动状态的粘性目录。创建此演示的最后一步是使用 IntersectionObserver
来设置目录 (ToC) 中的活动状态,因为您向上/向下滚动文档。
与上面的轮播指示器演示不同,我们不能仅仅通过移动一个圆点来实现这一点,因为 ToC 中的文字会进行调整。为了解决这种情况,我们需要将两个动画附加到 ToC 中的每个元素上
- 第一个动画是在适当的章节出现在文档底部边缘时,在视觉上激活 ToC 项目。
- 第二个动画是在适当的章节从文档顶部边缘滑出视野时,在视觉上停用 ToC 项目。
.section-nav li > a {
animation:
1s activate-on-enter linear forwards,
1s deactivate-on-leave linear forwards;
}
由于我们有两个动画,因此我们还需要创建两个滚动时间线,每个内容部分都有两个。以 #introduction
部分为例
@scroll-timeline section-introduction-enter {
scroll-offsets:
selector(#introduction) end 0,
selector(#introduction) end 1;
}
@scroll-timeline section-introduction-leave {
scroll-offsets:
selector(#introduction) start 1,
selector(#introduction) start 0;
}
一旦这两个时间线都链接到这两个动画,一切将按预期工作
.section-nav li > a[href"#introduction"] {
animation-timeline:
section-introduction-enter,
section-introduction-leave;
}
最后
我希望我已经说服您相信滚动链接动画规范所提供的潜力。
不幸的是,它目前仅在基于 Chromium 的浏览器中受支持,隐藏在标志后面。鉴于这种潜力,我个人希望 - 一旦规范确定最终语法 - 其他浏览器供应商也会效仿。
如果您也希望看到滚动链接动画在其他浏览器中实现,您可以积极地关注相关的浏览器问题。
通过积极地关注问题,我们开发人员可以向浏览器供应商表明我们对这些功能的兴趣。
需要启用哪个特定的实验性 Web 平台功能?我在 Chrome 91 中,没有看到“CSS 滚动链接动画”作为可用的实验。
嗨!启用“实验性 Web 平台功能”选项,然后重新启动浏览器。它可以在 Chrome 或 Chrome Canary 中启用。
感谢您对滚动时间线的概述,这是一个令人兴奋的功能,我非常渴望在未来的项目中使用它(虽然我喜欢 GSAP 的 ScrollTrigger,但我总是欢迎纯 CSS 的解决方案)。
我通常不太喜欢视差滚动效果,但我一直很喜欢 Firewatch 网站,我非常高兴看到您用它来演示这个功能!
这太令人兴奋了!
Chrome 何时计划将它从“实验性 Web 平台功能”标志中移出并进入主流浏览器?
您好!
我使用的是 Chrome Canary 110,启用了“实验性 Web 平台功能”,但页面上的功能对我不可见。任何功能都不可见。我该怎么办?
我很想探索它。