CSS Scroll-Driven Animations:原生滚动动画完全指南
CSS Scroll-Driven Animations:原生滚动动画完全指南
作者: Josh W. Comeau | 发布时间: 2026-05-13
核心要点
- Animation Timeline API:新的 CSS API 允许将关键帧动画映射到滚动进度而非时间。
- view() 函数:使用元素在视口中的位置作为动画输入,实现滚动触发效果。
- animation-range:精确控制动画开始和结束的位置(cover、contain、entry、exit)。
- Linked Timelines:将一个元素的滚动进度应用到另一个元素的动画,实现复杂交互。
- 原生性能:无需 JavaScript,浏览器原生实现,性能更好。
详细内容
核心概念
传统 CSS 关键帧动画基于时间:
@keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } .elem { animation: fadeIn 1000ms; }
Animation Timeline API 的核心创新:将关键帧映射到滚动距离而非时间:
.elem { animation: fadeIn; animation-timeline: view(); /* 使用视口位置 */ }
现在,元素从 0% (opacity: 0) 到 100% (opacity: 1) 的过渡不是基于时间,而是基于元素在视口中的位置。滚动页面会"擦拭"关键帧动画。
基础用法
最简单的使用方式是 animation-timeline: view():
.elem { animation: fadeIn; animation-timeline: view(); }
这会测量元素从进入视口到完全离开视口的完整旅程,将这段时间映射到关键帧动画的 0% 到 100%。
时序函数
可以像普通动画一样应用缓动曲线:
.box { --super-ease-out: cubic-bezier(0.15, 0.75, 0.35, 1); animation: spin var(--super-ease-out); animation-timeline: view(); }
甚至可以使用弹簧缓动:
.box { --spring: linear(0, 0.01, 0.04 1.8%, 0.161 3.7%, ...); animation: spin var(--spring); animation-timeline: view(); }
Animation Range 详解
cover(默认):从元素顶部进入视口开始,到底部离开视口结束。
contain:只在元素完全在视口内时测量。动画在元素完全可见时才开始。
entry:从元素开始进入视口开始,到元素完全进入视口结束。
exit:从元素开始离开视口开始,到元素完全离开视口结束。
.elem { animation: fadeIn linear; animation-timeline: view(); animation-range: entry; /* 只在进入时播放 */ }
范围百分比
更精确的控制:
.shape { animation: slideIn backwards; animation-timeline: view(); animation-range-start: cover 0%; animation-range-end: cover 50%; }
简写形式:
.shape { animation-range: cover 0% cover 50%; }
Scroll Progress Timeline
与 view progress 关注单个元素不同,scroll progress 关注整体滚动进度:
.readingIndicator { position: fixed; top: 0; left: 0; right: 0; height: 20px; background: red; transform-origin: left center; animation: expand linear; animation-timeline: scroll(); }
这创建了一个阅读进度条,随着用户滚动页面而增长。
Linked Timelines 高级用法
最强大但也最复杂的用法:将一个元素的滚动进度应用到另一个元素的动画。
main { timeline-scope: --tracked-elem; } .content { view-timeline: --tracked-elem; } .square { animation: fadeIn backwards, fadeOut forwards; animation-timeline: --tracked-elem, --tracked-elem; animation-range: entry, exit; }
关键机制:
- 在被跟踪元素上设置
view-timeline: --tracked-elem创建命名时间线 - 在动画元素上引用
animation-timeline: --tracked-elem - 使用
timeline-scope在共同祖先上声明变量,解决作用域问题
浏览器支持
当前状态(2026年5月):
- Chrome/Edge:完整支持
- Safari:支持 view() 和 scroll(),部分支持 linked timelines
- Firefox:正在实现中
渐进增强策略:
.elem { /* 基础样式 */ opacity: 0; } @supports (animation-timeline: view()) { .elem { opacity: 1; animation: fadeIn linear; animation-timeline: view(); animation-range: entry; } }
实际应用场景
1. 图片进入视口时淡入
img { animation: fadeIn linear; animation-timeline: view(); animation-range: entry; }
2. 元素进入时滑入,离开时滑出
.shape { animation: slideIn backwards, slideOut forwards; animation-timeline: view(), view(); animation-range: entry, exit; }
3. 阅读进度指示器
.progress { position: fixed; top: 0; left: 0; height: 4px; background: blue; transform-origin: left; animation: expand linear; animation-timeline: scroll(); }
结论
Animation Timeline API 是 CSS 动画的重大进步。它建立在现有的 CSS 原语之上,以一种优雅自然的方式扩展了关键帧动画的能力。
主要优势:
- 无需 JavaScript,性能更好
- 与现有动画系统无缝集成
- 声明式语法,更易维护
- 硬件加速,流畅度高
注意事项:
- 渐进增强是关键——始终提供合理的回退
- 复杂交互可能仍需 JavaScript
- 浏览器支持仍在完善中
Josh Comeau 总结道:"这个新 API 如此出色,它建立在现有的 CSS 原语之上,以一种优雅自然的方式。事实上,如果你熟悉 CSS 关键帧动画,你已经掌握了大部分需要知道的内容!"
对于 Web 开发者来说,现在是开始学习 scroll-driven animations 的最佳时机——未来已来,只是分布不均。