CSS 滚动驱动动画(Scroll-driven):`animation-timeline` 绑定滚动容器进度

CSS 滚动驱动动画:animation-timeline 绑定滚动容器进度

大家好,今天我们要深入探讨 CSS 滚动驱动动画,特别是如何利用 animation-timeline 属性将动画与滚动容器的进度紧密结合。滚动驱动动画是一种强大的技术,能够让网页内容随着用户的滚动行为而动态变化,从而创造更具吸引力和交互性的用户体验。

什么是滚动驱动动画?

传统 CSS 动画通常依赖于时间线,动画会根据预设的持续时间和关键帧序列自动播放。而滚动驱动动画则改变了这种模式,它将动画的进度与用户的滚动行为绑定在一起。也就是说,动画的播放不再由时间控制,而是由滚动容器的滚动进度控制。当用户滚动页面时,动画会相应地前进或后退,从而实现与滚动行为同步的视觉效果。

animation-timeline 属性:连接动画与滚动

animation-timeline 属性是实现滚动驱动动画的关键。它允许我们将动画与特定的时间线关联起来,而这个时间线可以是:

  • scroll():滚动容器的滚动进度。
  • view():元素在视口中的可见性比例。
  • none:禁用滚动驱动动画,回到传统的基于时间的动画。

scroll() 时间线:基于滚动容器的动画

scroll() 函数允许我们将动画与滚动容器的滚动进度绑定。它的语法如下:

animation-timeline: scroll(arguments);

arguments 可以包含以下选项:

  • root: 指定滚动容器。默认为 document (根滚动容器)。可以使用 CSS 选择器指定其他滚动容器。
  • source: 指定滚动条的方向。可以是 block (垂直滚动) 或 inline (水平滚动)。默认为 block

示例 1:简单的垂直滚动驱动动画

假设我们有一个 <div> 元素,我们希望它的背景颜色随着垂直滚动而改变。

<div class="animated-box">
  Scroll down to change the background color!
</div>
.animated-box {
  width: 200px;
  height: 200px;
  background-color: red;
  animation-name: changeBackgroundColor;
  animation-duration: auto; /* 关键: duration设置为auto */
  animation-timeline: scroll(); /* 使用默认的根滚动容器和垂直滚动 */
}

@keyframes changeBackgroundColor {
  0% {
    background-color: red;
  }
  100% {
    background-color: blue;
  }
}

在这个例子中,animation-duration 被设置为 auto。这意味着动画的持续时间由滚动容器的滚动长度决定。当页面滚动到结尾时,动画将完成。

示例 2:指定滚动容器

如果你的动画需要绑定到特定的滚动容器,而不是根滚动容器,你可以使用 root 选项:

<div class="scroll-container">
  <div class="animated-box">
    Scroll within the container!
  </div>
</div>
.scroll-container {
  width: 300px;
  height: 300px;
  overflow: auto; /* 必须设置 overflow */
}

.animated-box {
  width: 200px;
  height: 200px;
  background-color: green;
  animation-name: changeBackgroundColor;
  animation-duration: auto;
  animation-timeline: scroll(root: .scroll-container); /* 指定滚动容器 */
}

@keyframes changeBackgroundColor {
  0% {
    background-color: green;
  }
  100% {
    background-color: yellow;
  }
}

在这个例子中,animation-timeline: scroll(root: .scroll-container) 将动画绑定到类名为 .scroll-container 的元素。只有在这个容器内滚动时,动画才会播放。

示例 3:水平滚动驱动动画

如果要使用水平滚动驱动动画,可以使用 source 选项:

<div class="scroll-container horizontal">
  <div class="animated-box">
    Scroll horizontally!
  </div>
</div>
.scroll-container.horizontal {
  width: 300px;
  height: 200px;
  overflow-x: auto; /* 必须设置 overflow-x */
  white-space: nowrap; /* 防止内容换行 */
}

.scroll-container.horizontal > * {
  display: inline-block; /* 使子元素可以水平排列 */
  width: 200px; /* 设置子元素的宽度,以便可以水平滚动 */
  height: 100%;
}

.animated-box {
  width: 200px;
  height: 200px;
  background-color: purple;
  animation-name: changeBackgroundColor;
  animation-duration: auto;
  animation-timeline: scroll(root: .scroll-container.horizontal, source: inline); /* 指定水平滚动 */
}

@keyframes changeBackgroundColor {
  0% {
    background-color: purple;
  }
  100% {
    background-color: orange;
  }
}

在这个例子中,animation-timeline: scroll(root: .scroll-container.horizontal, source: inline) 将动画绑定到类名为 .scroll-container.horizontal 的元素的水平滚动。

view() 时间线:基于元素可见性的动画

view() 函数允许我们将动画与元素在视口中的可见性比例绑定。它的语法如下:

animation-timeline: view(arguments);

arguments 可以包含以下选项:

  • root: 指定视口。默认为 document (根视口)。可以使用 CSS 选择器指定其他视口。
  • inset: 定义一个插入值,用于调整元素被认为可见的阈值。 它可以是长度、百分比或 autoauto 值表示浏览器根据元素的特性(例如大小)自动计算插入值。 长度和百分比值定义了视口边缘的偏移量。 正值会缩小元素被认为可见的区域,而负值会扩大该区域。 插入值由四个值组成,分别对应于视口的顶部、右侧、底部和左侧边缘(顺时针方向)。可以使用一到四个值来指定插入值。单个值应用于所有四个边缘。两个值分别应用于顶部/底部和左侧/右侧边缘。三个值分别应用于顶部、左侧/右侧和底部边缘。

示例 4:基于元素可见性的动画

假设我们有一个 <div> 元素,我们希望它的透明度随着元素进入视口而改变。

<div class="animated-box">
  Fade in as you scroll into view!
</div>
.animated-box {
  width: 200px;
  height: 200px;
  background-color: lightblue;
  opacity: 0;
  animation-name: fadeIn;
  animation-duration: auto;
  animation-timeline: view(); /* 使用默认的根视口 */
}

@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

在这个例子中,当 .animated-box 元素开始进入视口时,它的透明度会从 0 逐渐变为 1。

示例 5:使用 inset 调整可见性阈值

<div class="animated-box">
  Fade in when almost fully in view!
</div>
.animated-box {
  width: 200px;
  height: 200px;
  background-color: lightgreen;
  opacity: 0;
  animation-name: fadeIn;
  animation-duration: auto;
  animation-timeline: view(inset: 20%); /* 元素完全可见 20% 后才开始动画 */
}

@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

在这个例子中,animation-timeline: view(inset: 20%) 表示只有当 .animated-box 元素至少 80% 可见时,动画才会开始播放。

animation-range 属性:精确控制动画的播放范围

animation-range 属性允许我们更精确地控制动画的播放范围。它可以与 animation-timeline 属性一起使用,以指定动画在滚动或可见性范围内的起始和结束点。

animation-range 的语法如下:

animation-range: <start-offset> <end-offset>;

<start-offset><end-offset> 可以是以下值:

  • normal: 默认值,表示动画从时间线的开始播放到结束。
  • <percentage>: 相对于滚动或可见性范围的百分比。例如,20% 表示从滚动或可见性范围的 20% 处开始或结束。
  • <length>: 表示基于长度的偏移量,通常不用于滚动驱动动画,因为动画的进度与长度(例如像素)没有直接关系。
  • cover: 用于 view() 时间线,表示动画从元素开始进入视口时开始,到完全离开视口时结束。
  • entry: 用于 view() 时间线,表示动画从元素开始进入视口时开始,到完全进入视口时结束。
  • exit: 用于 view() 时间线,表示动画从元素开始离开视口时开始,到完全离开视口时结束。

示例 6:使用 animation-range 控制动画播放范围

<div class="animated-box">
  Animate only in the middle of the scroll!
</div>
.animated-box {
  width: 200px;
  height: 200px;
  background-color: tomato;
  transform: translateX(-100px); /* 初始位置在视口外 */
  animation-name: moveIn;
  animation-duration: auto;
  animation-timeline: scroll();
  animation-range: 25% 75%; /* 动画只在滚动范围的 25% 到 75% 之间播放 */
}

@keyframes moveIn {
  0% {
    transform: translateX(-100px);
  }
  100% {
    transform: translateX(100px);
  }
}

在这个例子中,animation-range: 25% 75% 表示动画只在滚动范围的 25% 到 75% 之间播放。这意味着当页面滚动到 25% 时,动画开始播放,当页面滚动到 75% 时,动画结束播放。

示例 7:使用 animation-rangeview() 控制动画

<div class="animated-box">
  Fade in on entry, fade out on exit!
</div>
.animated-box {
  width: 200px;
  height: 200px;
  background-color: violet;
  opacity: 0;
  animation-name: fadeInOut;
  animation-duration: auto;
  animation-timeline: view();
  animation-range: entry exit; /* 进入视口时淡入,离开视口时淡出 */
}

@keyframes fadeInOut {
  entry {
    opacity: 1; /* 进入视口时 */
  }
  exit {
    opacity: 0; /* 离开视口时 */
  }
}

在这个例子中,animation-range: entry exit@keyframes 中的 entryexit 关键字一起使用,可以实现元素进入视口时淡入,离开视口时淡出的效果。

兼容性 considerations

animation-timelineanimation-range 属性是相对较新的 CSS 特性。 截至撰写本文时,它们在所有主流浏览器中都得到了良好的支持。 然而,为了确保在旧浏览器中的兼容性,你可以使用 polyfill 或渐进增强技术。

实际应用场景

滚动驱动动画可以用于创建各种各样的交互式和引人入胜的用户体验,例如:

  • 视差滚动效果: 通过让不同的元素以不同的速度滚动,可以创建深度感和沉浸感。
  • 进度条: 可以使用滚动进度来更新进度条,以显示用户在页面上的滚动进度。
  • 元素淡入/淡出: 可以使用元素可见性来控制元素的淡入和淡出效果。
  • 图像序列动画: 可以使用滚动进度来播放图像序列,从而创建简单的动画效果。
  • 自定义滚动指示器: 可以使用滚动进度来更新自定义滚动指示器的位置和外观。

代码示例:视差滚动效果

<div class="parallax-container">
  <div class="parallax-background"></div>
  <div class="parallax-content">
    <h1>Welcome!</h1>
    <p>Scroll down to see the parallax effect.</p>
  </div>
</div>
.parallax-container {
  position: relative;
  height: 100vh;
  overflow-x: hidden; /* 隐藏水平滚动条,防止出现不必要的滚动 */
}

.parallax-background {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-image: url("your-background-image.jpg"); /* 替换为你的背景图片 */
  background-size: cover;
  background-position: center;
  transform: translateZ(-1px) scale(2); /* 创建视差效果 */
  transform-origin: 0;
  z-index: -1; /* 放置在内容下方 */
  animation: parallaxScroll 0.1s linear forwards; /* 触发动画 */
  animation-timeline: scroll();
}

.parallax-content {
  position: relative;
  z-index: 1;
  padding: 50px;
  background-color: rgba(255, 255, 255, 0.8);
}

@keyframes parallaxScroll {
  to {
    transform: translateZ(-1px) scale(1.5); /* 滚动时缩小背景图像,增强视差效果 */
  }
}

在这个例子中,背景图像通过 transform: translateZ(-1px) scale(2) 创建了视差效果。animation-timeline: scroll() 将动画绑定到滚动进度,而 @keyframes parallaxScroll 定义了滚动时背景图像的缩小效果。

总结和应用建议

animation-timeline 属性为我们提供了一种强大的方式来创建滚动驱动动画,从而提升用户体验。 了解 scroll()view() 时间线以及 animation-range 属性的用法,我们可以创建各种各样的动态和引人入胜的视觉效果。 在实际应用中,要充分考虑性能问题,避免创建过于复杂的动画,并使用适当的优化技术来确保流畅的滚动体验。通过巧妙地运用这些技术,你可以为你的网站和应用程序注入更多的活力和互动性。

更多IT精英技术系列讲座,到智猿学院

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注