CSS动画Web开发前端JavaScript

CSS Scroll-Driven Animations:原生滚动动画完全指南

Josh W. Comeau··原文链接
收录于 2026/5/15 18:11:09

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;
}

关键机制:

  1. 在被跟踪元素上设置 view-timeline: --tracked-elem 创建命名时间线
  2. 在动画元素上引用 animation-timeline: --tracked-elem
  3. 使用 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 的最佳时机——未来已来,只是分布不均。