滚动条驱动的动画是 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%;
}
`;
我们非常高兴看到这项功能,因为它完美结合了效果和更好的体验,有助于提升我们的网页体验信号,从而提升搜索引擎优化效果。此外,由于学习曲线很短,因此它是每个电子商务网站的必备工具。我们还收到了其他团队的积极反馈和支持,他们建议我们利用 SDA 来覆盖更多用户历程。- Amit Kumar,redBus 高级工程经理。
Policybazaar
比较保险方案是用户在决策过程中反复执行的一项关键操作。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 时的注意事项
您可以为不支持的浏览器对滚动条驱动的动画进行 polyfill,例如使用 Scroll-timeline polyfill。如果您这样做,则需要进行额外的测试,以确保它能与您的框架协同工作,并且使用该 polyfill 的浏览器不会出现动画失败或卡顿问题。
在使用滚动条驱动的动画之前,您可以使用 CSS 中的 @supports
测试是否支持 animation-timeline。例如:
@supports (animation-timeline: scroll()) {
}
资源
- 滚动条驱动的动画演示
- 使用滚动条驱动的动画在滚动时为元素添加动画效果
- Codelab:CSS 滚动驱动型动画入门
- Chrome 扩展程序:滚动驱动型动画调试程序
- 滚动时间轴 Polyfill
- 您想报告 bug 或新功能吗?我们期待收到您的反馈!
探索本系列的其他文章,了解电子商务公司如何通过使用新的 CSS 和界面功能(例如视图转换、弹出式窗口、容器查询和 has()
选择器)受益。