滚动链接动画(Scroll-linked Animations)规范是一个即将到来的实验性的补充,它允许我们将动画进度与滚动进度相链接:当你向上和向下滚动容器时,链接的动画也会相应地前进或倒退。
我们在CSS-Tricks的前一篇文章中介绍了一些用例,这些用例都是由该规范提供的CSS@scroll-timeline at-rule和animation-timeline 属性驱动的--是的,没错:所有这些用例都是只使用HTML和CSS构建的。没有JavaScript。
除了我们通过滚动链接动画规范得到的CSS接口外,它还描述了一个实现滚动链接动画的JavaScript接口。让我们来看看ScrollTimeline 类,以及如何用Web Animations API来使用它。
Web Animations API。快速回顾
在CSS-Tricks网站上曾经介绍过Web Animations API(WAAPI)。作为一个简短的回顾,该API让我们能够构建动画,并通过JavaScript控制其播放。
以下面这个CSS动画为例,在页面的顶部有一个横条,并且:
- 从
red到darkred的动画,然后 - 从零宽到全宽的动画(通过缩放X轴)。
CodePen 嵌入回退
将CSS动画转换为WAAPI的对应代码,代码变成这样:
new Animation(
new KeyframeEffect(
document.querySelector('.progressbar'),
{
backgroundColor: ['red', 'darkred'],
transform: ['scaleX(0)', 'scaleX(1)'],
},
{
duration: 2500,
fill: 'forwards',
easing: 'linear',
}
)
).play();
CodePen 嵌入回退
或者,使用更简短的语法,用 Element.animate():
document.querySelector('.progressbar').animate(
{
backgroundColor: ['red', 'darkred'],
transform: ['scaleX(0)', 'scaleX(1)'],
},
{
duration: 2500,
fill: 'forwards',
easing: 'linear',
}
);
CodePen 嵌入回退
在这最后两个JavaScript例子中,我们可以分辨出两件事。首先,是一个keyframes 对象,它描述了哪些属性需要动画化:
{
backgroundColor: ['red', 'darkred'],
transform: ['scaleX(0)', 'scaleX(1)'],
}
第二是一个options 对象,它配置了动画的持续时间、缓和等:
{
duration: 2500,
fill: 'forwards',
easing: 'linear',
}
创建和附加一个滚动时间线
为了让我们的动画由滚动驱动--而不是时钟的单调滴答--我们可以保留我们现有的WAAPI代码,但需要通过附加一个ScrollTimeline 实例来扩展它。
这个ScrollTimeline 类允许我们描述一个AnimationTimeline ,其时间值不是由挂钟时间决定的,而是由滚动容器中的滚动进度决定的。它可以用几个选项来配置:
source:可滚动的元素,其滚动会触发激活并驱动时间线的进展。默认情况下,这是document.scrollingElement(即滚动整个文档的滚动容器)。- **
orientation*:*决定滚动的方向,它触发激活并驱动时间线的进展。默认情况下,这是vertical(或作为逻辑值的block)。 scrollOffsets:这些决定了有效的滚动偏移,按照orientation值指定的方向移动。它们构成了时间线处于活动状态的等距的进度区间。
这些选项被传递到构造函数中,比如说:
const myScrollTimeline = new ScrollTimeline({
source: document.scrollingElement,
orientation: 'block',
scrollOffsets: [
new CSSUnitValue(0, 'percent'),
new CSSUnitValue(100, 'percent'),
],
});
这些选项与CSS的@scroll-timeline 描述符完全相同,这不是巧合。这两种方法都能让你实现同样的结果,唯一的区别是你用什么语言来定义它们。
为了将我们新创建的ScrollTimeline 实例附加到一个动画上,我们将它作为第二个参数传入Animation 构造函数:
new Animation(
new KeyframeEffect(
document.querySelector('#progress'),
{ transform: ['scaleX(0)', 'scaleX(1)'], },
{ duration: 1, fill: 'forwards' }
),
myScrollTimeline
).play();
CodePen嵌入回退
当使用Element.animate() 语法时,将其设置为options 对象中的timeline 选项:
document.querySelector("#progress").animate(
{
transform: ["scaleX(0)", "scaleX(1)"]
},
{
duration: 1,
fill: "forwards",
timeline: myScrollTimeline
}
);
CodePen Embed Fallback
有了这段代码,动画就由我们的ScrollTimeline 实例驱动,而不是默认的DocumentTimeline 。
目前Chromium的实验性实现使用scrollSource ,而不是source 。这就是你在代码例子中看到source 和scrollSource 的原因。
关于浏览器兼容性的话
在写这篇文章的时候,只有Chromium的浏览器支持ScrollTimeline 类,在一个特性标志后面。幸好有Robert Flack的Scroll-Timeline Polyfill,我们可以用它来填补所有其他浏览器不支持的空白。事实上,本文中的所有演示都包含了它。
Polyfill可以作为一个模块使用,如果没有检测到支持,它可以自己注册。要包含它,请在你的JavaScript代码中添加以下import 语句:
import 'https://flackr.github.io/scroll-timeline/dist/scroll-timeline.js';
如果浏览器不支持,Polyfill也会注册所需的CSS类型对象模型类。(👀看着你,Safari。)
高级滚动时间线
除了绝对的偏移,滚动链接的动画也可以与基于元素的偏移一起工作。
使用这种类型的滚动偏移,动画是基于滚动容器中的一个元素的位置。
通常情况下,这被用来在一个元素进入滚动端口时为其制作动画,直到它离开滚动端口;例如,当它正在相交时。
一个基于元素的偏移由三个部分组成,描述它:
target:被追踪的DOM元素。edge:这就是ScrollTimeline'的source,看着target,让它穿过。threshold:一个从0.0到1.0的数字,表示target在edge的滚动端口中的可见程度。(你可能从IntersectionObserver.)
这里有一个可视化的方法。
CodePen 嵌入偏移
如果你想了解更多关于基于元素的偏移,包括它们如何工作,以及常用偏移的例子,请查看这篇文章。
基于元素的偏移也被JSScrollTimeline 接口所支持。要定义一个,使用一个常规对象:
{
target: document.querySelector('#targetEl'),
edge: 'end',
threshold: 0.5,
}
通常情况下,你将两个这样的对象传入scrollOffsets 属性:
const $image = document.querySelector('#myImage');
$image.animate(
{
opacity: [0, 1],
clipPath: ['inset(45% 20% 45% 20%)', 'inset(0% 0% 0% 0%)'],
},
{
duration: 1,
fill: "both",
timeline: new ScrollTimeline({
scrollSource: document.scrollingElement,
timeRange: 1,
fill: "both",
scrollOffsets: [
{ target: $image, edge: 'end', threshold: 0.5 },
{ target: $image, edge: 'end', threshold: 1 },
],
}),
}
);
下面的演示中就使用了这段代码。这是我上次所讲的效果的一个JavaScript重制版:当一个图像滚动到视口时,它就会淡入并变成无遮挡的。
CodePen 嵌入回退
更多的例子
这里还有一些我编写的例子。
水平滚动部分
这是以Cameron Knight的演示为基础的,它有一个水平滚动部分。它的行为类似,但使用ScrollTimeline ,而不是GSAP的ScrollTrigger 。
CodePen嵌入回退
更多关于这段代码的工作原理,以及查看纯CSS版本,请参考此文章。
CoverFlow
还记得iTunes的CoverFlow吗?嗯,这里有一个用ScrollTimeline:
CodePen嵌入回退
由于一个错误,这个演示在Chromium中的表现并不像预期的那样100%。问题是开始和结束位置的计算不正确。你可以在这个Twitter主题中找到解释(有视频)。
关于这个演示的更多信息可以在这篇文章中找到。
使用CSS还是JavaScript?
除了使用的语言外,在滚动链接动画中使用CSS或JavaScript并没有真正的区别:两者都使用相同的概念和结构。本着真正的渐进式增强的精神,我将抓住CSS来实现这些效果。
然而,正如我们前面所提到的,在撰写本文时,对基于CSS的实现的支持是相当差的:
- Chromium在一个功能标志后面支持它。
- 火狐正在为它准备一些工作。
- Safari还没有消息。
由于这种糟糕的支持,在这个非常时刻,你肯定会用JavaScript走得更远。只要确保你的网站在禁用JavaScript时也能被浏览和消费。 😉