配了三年滚动动画,今天才发现 npm 上那个库根本不用装了——scroll-driven animations 把这件事彻底变了
配了三年滚动动画,今天发现 npm 上那个库根本不用装了——准确地说,整个 JS 动画库可以删了——reading progress bar、reveal 动画、parallax、sticky header 动画,全部。现在浏览器自己会做,而且跑在合成器线程上,不占主线程。
这件事的变化是从 IntersectionObserver 开始的,但真正的账是一次把整个依赖链都清了。
现在浏览器自己会认路了
CSS scroll-driven animations 给 CSS 动画引入了两个新时间轴:
animation-timeline: scroll()— 时间轴是滚动容器的滚动进度,滚动 0% 时对应 from,100% 时对应 toanimation-timeline: view()— 时间轴是元素在视口中的可见性,从进入视口到离开视口,对应 from 到 to
不再需要 animation-duration,因为时间轴从「秒」换成了「滚动进度」。
配合 animation-range 可以精确控制动画在哪个阶段触发:
/* 元素进入视口的前 30% 时播放 */
animation-range: entry 0% entry 30%;
/* 元素完全离开视口时播放 */
animation-range: exit 0% exit 100%;
/* 元素完整覆盖视口期间播放 */
animation-range: contain;
/* reading progress bar */
@keyframes grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
.progress-bar {
animation: grow linear;
animation-timeline: scroll();
}
/* reveal 动画 */
@keyframes fade-up {
from { opacity: 0; transform: translateY(24px); }
to { opacity: 1; transform: translateY(0); }
}
.card {
animation: fade-up linear both;
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
两件事以前要靠一个 JS 库,现在三行 CSS。
真实生产数据:JS 少了 12%,INP 从 320ms 掉到 148ms
Mintec 三个生产项目迁移后测出来的数字:
| 旧方案(IntersectionObserver) | CSS scroll-driven animations | |
|---|---|---|
| JS 增加量 | ~3KB(base)+ 每元素逻辑 | 0 KB |
| 主线程占用 | 高(回调在主线程执行) | 无(合成器线程) |
| INP 影响 | +30~80ms | 0ms |
| 定时控制 | 一次性(开关切换) | 连续(滚动进度驱动) |
Editorial 平台 200K 月活,迁移后 JS bundle 从 180KB 缩到 158KB,INP 从「Needs Improvement」的 320ms 降到「Good」的 148ms。不是 CSS 本身比 JS 快,而是移除了 24 个 IntersectionObserver 实例,滚动时主线程空出来了。
安装成本:零
不需要 npm install AOS.js 或 npm install GSAP ScrollTrigger,不需要引入,不需要配置,不需要学习库的 API。三行 CSS,全部在浏览器里。
渐进增强
/* 不支持的浏览器:元素保持可见状态 */
.element {
opacity: 1;
transform: none;
}
@supports (animation-timeline: view()) {
.element {
animation: fade-in linear both;
animation-timeline: view();
animation-range: entry;
}
}
浏览器支持
Chrome 115+、Edge 115+、Safari 18+、Firefox 126+ 全球覆盖率约 90%,生产环境可用。
下一步
先把现有的 IntersectionObserver reveal 动画迁移过去,从最简单的 reading progress bar 开始。只用 transform 和 opacity,不走合成器线程的属性不动。复杂序列动画(多元素联动、physics-based)仍保留 JS。
评论区
登录后可评论。