长久以来,创建基于页面滚动位置触发的动画,往往需要监听scroll事件、计算偏移量并手动更新样式。这种方式不仅代码繁琐,还容易引发性能问题。2024年底至2025年初,CSS Scroll-Driven Animations 规范在主流浏览器中全面落地,让我们可以直接在样式表中声明滚动与动画的关联——就像把时间轴交给滚动条一样自然。本文将带你从基础概念到高阶案例,彻底掌握这一革命性的动画机制。
一、核心概念:两种时间轴
传统CSS动画使用文档时间轴(animation-timeline: auto),动画从页面加载开始按秒运行。而滚动驱动动画将滚动进度映射为动画的进度,分为两类时间轴:
- Scroll Progress Timeline(滚动进度时间轴):绑定到某个滚动容器的滚动进度,从0%到100%。适用于页面整体的进度指示器、视差效果。
- View Progress Timeline(视图进度时间轴):基于元素进出滚动视口的可见性进度,可以细致控制元素从“即将进入”到“完全离开”的各个阶段。适合制作进入视口动画、列表项逐个显示。
这两种时间轴分别通过 scroll() 和 view() 函数创建,并赋值给 animation-timeline 属性。动画本身仍使用熟悉的 @keyframes 定义,只是驱动源从“时间”变成了“空间”。
二、基础实战:阅读进度条
构建一个固定在页面顶部的进度条,随着页面滚动从0%增长到100%。无需任何JavaScript。
<!-- HTML结构 -->
<div class="progress-bar"></div>
<!-- CSS关键代码 -->
.progress-bar {
position: fixed;
top: 0;
left: 0;
height: 4px;
background: linear-gradient(90deg, #ff6b6b, #4ecdc4);
/* 核心声明:绑定到最近的滚动容器(通常是根滚动器) */
animation: grow-progress linear;
animation-timeline: scroll();
transform-origin: left;
}
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
代码解析:scroll() 函数无参数时指向最近的祖先滚动容器,通常是文档根元素。动画 grow-progress 使用 scaleX 从0到1,动画持续时间由滚动进度决定——滚动条在顶部时进度为0%,滚动到底部时进度为100%。进度条长度会自动适配页面内容高度。
三、实战案例一:视差滚动英雄区
让头部背景图像以比内容更慢的速度滚动,营造层次感。再叠加文字透明度变化。
<div class="hero">
<div class="hero-bg"></div>
<div class="hero-content">
<h1>探索新世界</h1>
<p>向下滚动体验</p>
</div>
</div>
.hero {
position: relative;
height: 100vh;
overflow: hidden;
}
.hero-bg {
position: absolute;
inset: -20%;
background: url('mountain.jpg') center/cover;
animation: parallax-bg linear;
animation-timeline: scroll();
}
@keyframes parallax-bg {
to { transform: translateY(15%); }
}
.hero-content {
position: relative;
z-index: 1;
animation: fade-content linear;
animation-timeline: scroll();
}
@keyframes fade-content {
to { opacity: 0.2; transform: translateY(-30%); }
}
这里同时驱动了两个动画:背景图像向下移动15%(速度慢于实际滚动),内容文字向上移动并淡出。整个英雄区在滚动过程中呈现出丰富的层次过渡,而这一切都是声明式的。
四、实战案例二:列表项逐个淡入(View Timeline)
当文章中的卡片列表滚动进入视口时,各卡片依次淡入上浮。这是典型的视图进度时间轴应用。
<div class="card-list">
<div class="card">内容块1</div>
<div class="card">内容块2</div>
<div class="card">内容块3</div>
<div class="card">内容块4</div>
</div>
.card {
animation: slide-in linear;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}
@keyframes slide-in {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
关键点解读:
– animation-timeline: view(); 为每个.card创建独立的视图时间轴,根据其自身在滚动视口中的位置计算进度。
– animation-range 定义了动画生效区间:entry 0%(元素即将进入视口底部边缘)到 entry 100%(元素完全进入视口顶部边缘)。这样卡片在开始可见时立即触发动画,到达完全可见位置时恰好结束。
– 没有使用任何延迟或错开属性,但实际效果中卡片会因为各自进入视口的时间不同而自然形成基于滚动位置的错开动画,完美替代了以往需要手动计算IntersectionObserver和transition-delay的方案。
五、高级技巧:精确控制动画区间与命名时间线
为了更精细地控制动画触发时机,animation-range 支持多样化的值,甚至可以为多个元素共享同一个命名时间线。
5.1 自定义动画区间
animation-range 可通过 contain、exit 等关键字或百分比组合出丰富阶段:
entry:元素从视口外开始进入,到完全进入。exit:元素从完全可见到完全离开视口。contain:元素完全在视口内时触发。- 也可混合如
entry 20% exit 80%。
5.2 共享时间轴与CSS变量联动
当多个元素需要完全同步于同一个滚动进度时,可以定义一个命名滚动时间轴,然后复用。
/* 在滚动容器上定义命名时间轴 */
.scroller {
scroll-timeline-name: --main-timeline;
scroll-timeline-axis: block; /* 垂直滚动 */
overflow-y: scroll;
}
/* 多个动画引用同一条时间轴 */
.child-a {
animation: moveX linear;
animation-timeline: --main-timeline;
}
.child-b {
animation: rotate linear;
animation-timeline: --main-timeline;
}
这种模式非常适用于仪表盘联动、多元素协同视差场景,而且可以搭配 CSS 变量动态调整关键帧中的属性值。
六、性能与可访问性考量
滚动驱动动画的优势不仅在于代码量减少,更在于性能:浏览器可以在合成器线程上直接处理这些动画,无需主线程参与样式计算或布局。以下是优化建议:
- 尽量只使用
transform和opacity进行动画,避免触发重排的属性(如width、height、top)。 - 对于不需要动画的元素,使用
animation: none重置,避免意外继承时间轴。 - 对于可能引起晕动症的用户,提供
prefers-reduced-motion媒体查询回退:
@media (prefers-reduced-motion: reduce) {
.card, .hero-bg {
animation: none !important;
}
}
这种简单的回退可以禁用所有滚动驱动动画,尊重用户系统设置。
七、浏览器兼容与渐进增强
截至2025年初,Chrome、Edge、Safari、Firefox均已支持Scroll-Driven Animations的核心功能。对于尚未支持的浏览器,动画将静默失效,元素保持原始状态。因此务必确保初始状态是页面可用的,动画仅作为增强体验。例如卡片列表默认就应是可见的,动画只增添过渡效果。
你可以使用特性查询来提供回退样式:
/* 检测是否支持scroll-driven动画 */
@supports (animation-timeline: scroll()) {
.progress-bar {
animation: grow-progress linear;
animation-timeline: scroll();
}
}
/* 不支持的情况下,可以使用简单的不动进度条或隐藏 */
@supports not (animation-timeline: scroll()) {
.progress-bar {
display: none;
}
}
八、总结
Scroll-Driven Animations 将CSS动画的舞台从“时间”扩展到了“空间”,让前端开发者能够以声明式、高性能的方式构建滚动交互。从进度条到视差、从列表淡入到复杂的时间线联动,这些以往需要大量脚本的体验如今只需要几行CSS。本文的案例全部可以独立运行,你只需将它们整合进自己的项目中,即可立即感受到生产力与流畅度的双重提升。
当设计稿上出现“滚动到此处时出现动画”的需求时,不妨先想一想:能否用CSS时间轴解决? 也许你会发现,浏览器的内置能力已经足够强大,而JavaScript只需退居幕后,处理那些真正需要逻辑控制的部分。

