滚动驱动的动画是 Web 上的一种常见用户体验模式。滚动驱动的动画与滚动容器的滚动位置相关联。这意味着,当您向上或向下滚动时,关联的动画会直接向前或向后快进/快退。例如,视差背景图片或阅读指示器等效果会随着您滚动而移动。
开发者通常使用 JavaScript 来响应主线程上的滚动事件,从而创建滚动驱动的动画。这使得很难创建与滚动同步且性能出色的滚动驱动型动画,因为滚动事件是异步传送的,并且由于位于主线程上,通常会导致卡顿。
不过,随着浏览器中推出新的 CSS 和界面功能,您现在可以创建声明式滚动驱动动画。借助滚动时间轴和视图时间轴(这两个新概念可与现有的 Web Animations API (WAAPI) 和 CSS Animations API 集成),您现在只需几行代码,即可在主线程中运行流畅的滚动驱动型动画。在本案例研究中,了解 Tokopedia、redBus 和 Policybazaar 如何通过这项新功能获益。
Tokopedia
Tokopedia 将之前的自定义 JavaScript 实现替换成了滚动驱动型动画,以优化网页性能,并提升整个电子商务转化漏斗中的整体浏览体验。
与使用传统 JavaScript 滚动事件相比,我们成功将代码行数最多减少了 80%,并发现滚动时的平均 CPU 使用率从 50% 降到了 2% Andy Wihalim,Tokopedia 高级软件工程师
代码
以下实现使用 scroll()
函数设置匿名滚动进度时间轴,以控制 CSS 动画的进度。顶部粘性栏的可见性会根据定义的 animationRange
内的滚动位置而变化。
const toggleBar = keyframes({
to: { height: 48 },
});
export const cssWrapper = css({
position: 'fixed',
left: 0,
width: '100vw',
pointerEvents: 'none',
marginTop: 120,
height: 0,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end',
animation: `${toggleBar} linear both`,
animationTimeline: 'scroll()',
animationRange: '20px 70px',
});
redBus
redBus 在其推荐活动着陆页上为移动设备和桌面设备提供了不同的动画,该着陆页会在转化漏斗的早期阶段向所有用户显示。借助滚动驱动的动画,他们可以将这些自定义 JavaScript 实现替换为 CSS,以实现相同的效果。
使用场景
带有图片揭示(适用于移动设备)和封面流式(适用于桌面设备)的照片库。
代码(手机)
在前面的示例中,Tokopedia 使用了匿名滚动进度时间轴。在以下代码中,redBus 使用命名视图进度时间轴。此动画会更改元素最接近的祖先滚动条(在本例中为照片库滚动条)中定义的 animation-range
内的 <img>
元素的 opacity
和 clip-path
。
const reveal = keyframes`
from {
opacity: 0;
clip-path: inset(45% 20% 45% 20%);
}
to {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}`
const CardImage = styled.div`
width: 100%;
height: 100%;
img {
border-top-left-radius: 0.75rem;
border-top-right-radius: 0.75rem;
height: 100%;
width: 100%;
object-fit: cover;
view-timeline-name: --revealing-image;
view-timeline-axis: block;
/* Attach animation, linked to the View Timeline */
animation: linear ${reveal} both;
animation-timeline: --revealing-image;
/* Tweak range when effect should run*/
animation-range: entry 25% cover 50%;
}
`;
我们非常高兴看到此功能,因为它将性能与更好的体验完美结合,提升了网页体验的 SEO 信号。此外,由于学习曲线很短,因此它是每个电子商务网站的必备工具。我们还获得了其他团队的积极反馈和支持,以利用 SDA 拓展用户体验。- Amit Kumar,redBus 高级工程经理。
政策集市
比较保险方案是用户在决策过程中反复执行的一项关键操作。使用滚动驱动的动画,Policybazaar 会缩小低优先级元素的大小,以响应用户滚动表格的情况。这不仅带来了流畅的滚动体验,还提高了可读性。
借助滚动驱动型动画,我们能够最大限度地扩大视口空间,让用户能够比较方案,从而确保专注且整洁有序的阅读体验。- Rishabh Mehrotra,PolicyBazaar 人寿保险业务部门设计主管。
代码
与 Tokopedia 中的前一个示例类似,Policybazaar 使用 scroll()
函数设置匿名滚动进度时间轴,以控制 CSS 动画的进度。在本例中,根据定义的 animation-range
中的滚动位置缩小字体大小并淡出标题。
@supports (animation-timeline: scroll()) {
.plan-comparison .inner-header {
animation: move-and-fade-header linear both;
}
.plan-comparison .left-side {
animation: shrink-name linear both;
}
.plan-comparison .inner-header, .plan-comparison .left-side {
animation-timeline: scroll();
animation-range: 0 150px;
}
}
@keyframes move-and-fade-header {
to {
translate: 0% -5%;
top:103px;
}
}
@keyframes shrink-name {
to {
font-size: 1.5rem;
}
}
滚动条驱动的动画是整个用户体验历程中的常见模式
所有精选的电子商务公司都在包含卡片的页面上使用了滚动驱动型动画,通过为卡片添加动画效果来吸引用户的注意力。以下示例展示了在用户体验历程的不同部分对卡片应用滚动效果。通常,这可以通过使用匿名视图进度时间轴来实现,以控制自定义 CSS 动画的进度,如下面的 CSS 代码段所示。
@keyframes animate-in {
0% { opacity: 0; transform: translateY(10%); }
100% { opacity: 1; transform: translateY(0); }
}
@keyframes animate-out {
0% { opacity: 1; transform: translateY(0); }
100% { opacity: 0; transform: translateY(-10%); }
}
.flyin_animate {
animation: animate-in linear forwards;
animation-timeline: view();
animation-range: entry;
}
redBus(首页)
Policybazaar(商品详情页)
Tokopedia(商品详情页面)
使用 Scroll-driven Animations API 时的注意事项
您可以为不支持的浏览器使用 Scroll-timeline polyfill 等方法为滚动条驱动的动画实现 polyfill。如果您这样做,则需要进行额外的测试,以确保它能与您的框架协同工作,并且使用该 polyfill 的浏览器不会出现动画失败或卡顿问题。
在使用滚动条驱动的动画之前,您可以使用 CSS 中的 @supports
测试是否支持 animation-timeline。例如:
@supports (animation-timeline: scroll()) {
}
资源
- 滚动条驱动的动画演示
- 使用滚动条驱动的动画,在滚动时为元素添加动画效果
- Codelab:CSS 滚动驱动型动画入门
- Chrome 扩展程序:滚动驱动型动画调试程序
- 滚动时间轴 Polyfill
- 您想报告 bug 或新功能吗?我们期待收到您的反馈意见!
敬请阅读本系列中的其他文章,这些文章介绍了电子商务公司如何通过使用新的 CSS 和界面功能(例如视图过渡、弹出式窗口、容器查询和 has()
选择器)获益。