CSS 滚动驱动动画:让页面动起来的新维度

代码如诗,滚动如歌。让我们用滚动驱动动画的魔法,为用户带来沉浸式的浏览体验。

什么是滚动驱动动画?

滚动驱动动画(Scroll-driven Animations)是 CSS 中一项革命性的特性,它允许动画的进度直接与页面滚动位置关联。这意味着我们可以创建与滚动行为紧密同步的动画效果,为用户带来更加流畅和自然的体验。

核心概念

1. 滚动时间线(Scroll Timeline)

滚动时间线将滚动容器的滚动位置映射到动画时间轴。

/* 定义滚动时间线 */
.scroller {
  scroll-timeline: --my-timeline y;
}

/* 使用滚动时间线 */
.animated-element {
  animation: my-animation linear;
  animation-timeline: --my-timeline;
}

2. 视口时间线(View Timeline)

视口时间线基于元素在视口中的可见性驱动动画。

/* 定义视口时间线 */
.element {
  view-timeline: --view-timeline;
}

/* 使用视口时间线 */
.animated-element {
  animation: fade-in linear;
  animation-timeline: --view-timeline;
}

3. 动画范围(Animation Range)

动画范围定义了动画在滚动时间线中的起始和结束位置。

.animated-element {
  animation: fade-in linear;
  animation-timeline: view();
  animation-range: entry 0% cover 50%;
}

基础实现

1. 基本滚动动画

/* 滚动容器 */
.scroll-container {
  height: 100vh;
  overflow-y: scroll;
  scroll-timeline: --scroll-timeline y;
}

/* 动画元素 */
.animated-box {
  width: 100px;
  height: 100px;
  background: #667eea;
  animation: rotate-and-scale linear;
  animation-timeline: --scroll-timeline;
}

@keyframes rotate-and-scale {
  from {
    transform: rotate(0deg) scale(1);
    background: #667eea;
  }
  to {
    transform: rotate(360deg) scale(1.5);
    background: #764ba2;
  }
}

2. 视口进入动画

/* 渐显效果 */
.fade-in-section {
  opacity: 0;
  transform: translateY(50px);
  animation: fade-in-up linear;
  animation-timeline: view();
  animation-range: entry 0% cover 30%;
}

@keyframes fade-in-up {
  from {
    opacity: 0;
    transform: translateY(50px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

3. 进度指示器

/* 进度条 */
.progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  height: 4px;
  background: linear-gradient(90deg, #667eea, #764ba2);
  transform-origin: left;
  animation: progress linear;
  animation-timeline: scroll();
}

@keyframes progress {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

实际应用场景

1. 视差滚动效果

<div class="parallax-container">
  <div class="parallax-layer layer-1">
    <img src="background.jpg" alt="背景">
  </div>
  <div class="parallax-layer layer-2">
    <h1>欢迎来到我的网站</h1>
  </div>
  <div class="content">
    <p>页面内容...</p>
  </div>
</div>
.parallax-container {
  height: 200vh;
  position: relative;
}

.parallax-layer {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.layer-1 {
  animation: parallax-bg linear;
  animation-timeline: scroll();
}

.layer-1 img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.layer-2 {
  animation: parallax-text linear;
  animation-timeline: scroll();
}

@keyframes parallax-bg {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(100px);
  }
}

@keyframes parallax-text {
  from {
    transform: translateY(0);
    opacity: 1;
  }
  to {
    transform: translateY(-200px);
    opacity: 0;
  }
}

2. 图片画廊

<div class="gallery">
  <div class="gallery-item">
    <img src="image1.jpg" alt="图片1">
    <div class="caption">图片 1</div>
  </div>
  <div class="gallery-item">
    <img src="image2.jpg" alt="图片2">
    <div class="caption">图片 2</div>
  </div>
  <!-- 更多图片 -->
</div>
.gallery {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding: 2rem;
}

.gallery-item {
  position: relative;
  border-radius: 12px;
  overflow: hidden;
  opacity: 0;
  transform: scale(0.8);
  animation: gallery-reveal linear;
  animation-timeline: view();
  animation-range: entry 10% cover 40%;
}

.gallery-item img {
  width: 100%;
  height: 400px;
  object-fit: cover;
}

.gallery-item .caption {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 1.5rem;
  background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
  color: white;
  transform: translateY(100%);
  animation: caption-reveal linear;
  animation-timeline: view();
  animation-range: entry 30% cover 50%;
}

@keyframes gallery-reveal {
  from {
    opacity: 0;
    transform: scale(0.8);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes caption-reveal {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}

3. 文字揭示效果

<div class="text-reveal-container">
  <h1 class="reveal-text">探索无限可能</h1>
  <p class="reveal-text">用代码创造未来</p>
</div>
.text-reveal-container {
  height: 200vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rem;
}

.reveal-text {
  font-size: 3rem;
  font-weight: bold;
  background: linear-gradient(90deg, #667eea, #764ba2);
  background-size: 0% 100%;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: text-reveal linear;
  animation-timeline: view();
  animation-range: entry 0% cover 50%;
}

@keyframes text-reveal {
  from {
    background-size: 0% 100%;
  }
  to {
    background-size: 100% 100%;
  }
}

高级技巧

1. 多个动画组合

.complex-animation {
  animation: 
    fade-in linear,
    slide-up linear,
    scale-up linear;
  animation-timeline: view();
  animation-range: 
    entry 0% cover 30%,
    entry 10% cover 40%,
    entry 20% cover 50%;
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slide-up {
  from { transform: translateY(100px); }
  to { transform: translateY(0); }
}

@keyframes scale-up {
  from { transform: scale(0.8); }
  to { transform: scale(1); }
}

2. 水平滚动动画

.horizontal-scroll-container {
  overflow-x: scroll;
  scroll-timeline: --horizontal-timeline x;
}

.horizontal-scroll-item {
  animation: horizontal-move linear;
  animation-timeline: --horizontal-timeline;
}

@keyframes horizontal-move {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-100%);
  }
}

3. 粘性头部效果

.sticky-header {
  position: sticky;
  top: 0;
  background: white;
  animation: header-shrink linear;
  animation-timeline: scroll();
  animation-range: 0 200px;
}

@keyframes header-shrink {
  from {
    padding: 2rem;
    font-size: 2rem;
  }
  to {
    padding: 1rem;
    font-size: 1.5rem;
  }
}

性能优化

  1. 使用 will-change:提前告知浏览器哪些属性将发生变化
  2. 避免复杂计算:滚动动画应该尽量简单
  3. 使用 transform 和 opacity:这些属性性能最好
  4. 限制动画范围:使用 animation-range 限制动画触发范围
.optimized-animation {
  will-change: transform, opacity;
  animation: simple-animation linear;
  animation-timeline: view();
  animation-range: entry 0% cover 30%;
}

@keyframes simple-animation {
  from {
    transform: translateY(50px);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

浏览器兼容性

浏览器支持情况
Chrome✅ 115+
Edge✅ 115+
Safari🚧 开发中
Firefox🚧 开发中

回退方案

/* 现代浏览器 */
@supports (animation-timeline: view()) {
  .animated-element {
    animation: fade-in linear;
    animation-timeline: view();
  }
}

/* 旧浏览器回退 */
@supports not (animation-timeline: view()) {
  .animated-element {
    opacity: 1;
    transform: none;
  }
}

最佳实践

  1. 渐进增强:为不支持滚动驱动动画的浏览器提供回退方案
  2. 性能优先:避免在低端设备上使用复杂的滚动动画
  3. 用户体验:确保动画不会干扰内容的可读性
  4. 可访问性:尊重用户的减少动画偏好设置
@media (prefers-reduced-motion: reduce) {
  .animated-element {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

总结

滚动驱动动画为 Web 开发带来了全新的可能性,让我们能够创建与滚动行为紧密同步的动画效果。通过掌握这项技术,我们可以为用户带来更加沉浸和自然的浏览体验。

滚动不仅仅是导航的方式,更是叙事的节奏。让我们用滚动驱动动画的魔法,创造出令人惊叹的网页体验,展现前端技术的无限可能。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐