配了三年滚动动画,今天才发现 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% 时对应 to
  • animation-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.jsnpm 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 开始。只用 transformopacity,不走合成器线程的属性不动。复杂序列动画(多元素联动、physics-based)仍保留 JS。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 11 阅读