CSS `Scroll Timeline` / `View Timeline` (提案):基于滚动或元素可见性的动画

各位靓仔靓女们,早上好/下午好/晚上好! 今天咱们来聊聊CSS动画界的新晋网红——Scroll Timeline和View Timeline。 这玩意儿,说白了,就是让你动画不再傻乎乎地定时播放,而是跟着你的滚动条或者元素可见性来“摇摆”。 听起来是不是有点意思?

第一部分: 动画的“前世今生”: 传统动画的局限性

在Scroll Timeline和View Timeline横空出世之前,咱们用的CSS动画,要么是靠animation-duration硬撑,要么就是用JS监听滚动事件,手动控制动画进度。

  • animation-duration大法

    这玩意儿简单粗暴,直接给动画定个时间,然后让它自己演。 优点是配置简单,缺点嘛,就是太死板。 你滚动快了,它还是按自己的节奏来;你滚动慢了,它也一样。 动画和用户行为完全脱节,毫无互动性可言。

    .element {
      animation-name: slide-in;
      animation-duration: 2s; /* 动画持续2秒 */
    }
    
    @keyframes slide-in {
      from {
        transform: translateX(-100%);
      }
      to {
        transform: translateX(0);
      }
    }

    这种动画,就像一个设定好程序的机器人,不管你做什么,它都按照既定的路线执行。

  • JS监听大法

    这玩意儿稍微高级点,通过JS监听scroll事件,拿到滚动条的位置,然后根据滚动条的位置来控制动画的进度。 优点是可以精确控制动画,缺点是代码量大,而且性能可能会有问题,特别是滚动事件触发频率非常高的时候。

    const element = document.querySelector('.element');
    
    window.addEventListener('scroll', () => {
      const scrollPosition = window.scrollY;
      const elementOffsetTop = element.offsetTop;
      const windowHeight = window.innerHeight;
    
      // 计算元素进入视口的百分比
      const progress = Math.min(1, Math.max(0, (scrollPosition + windowHeight - elementOffsetTop) / windowHeight));
    
      // 根据百分比来设置元素的样式
      element.style.transform = `translateX(${progress * 100 - 100}%)`;
    });

    这种动画,就像一个拿着遥控器的木偶师,你需要时刻关注滚动条的位置,然后手动控制木偶的动作。

总之,传统动画要么太死板,要么太麻烦,难以满足我们对互动性更强的动画的需求。

第二部分: Scroll Timeline: 让动画跟着滚动条“跳舞”

Scroll Timeline的出现,就是为了解决传统动画的这些问题。 它可以让你把动画的进度和滚动条的位置关联起来,让动画随着滚动条的滚动而“跳舞”。

  • scroll-timeline-sourcescroll-timeline-axis

    要使用Scroll Timeline,首先需要告诉浏览器,你要用哪个滚动条来驱动动画。 这就要用到scroll-timeline-sourcescroll-timeline-axis这两个属性。

    • scroll-timeline-source: 指定滚动容器。 可以是none(默认值,禁用滚动时间线)、self(当前元素作为滚动容器)或者一个CSS选择器(指向页面上的其他元素)。
    • scroll-timeline-axis: 指定滚动方向。 可以是block(垂直滚动)、inline(水平滚动)、vertical(垂直滚动,效果同block)或者horizontal(水平滚动,效果同inline)。
    .container {
      overflow-y: scroll; /* 确保容器可滚动 */
      height: 300px;
    }
    
    .element {
      animation-name: slide-in;
      animation-duration: 1s;
      animation-timeline: scroll-timeline; /* 启用滚动时间线 */
      scroll-timeline-source: .container; /* 指定滚动容器 */
      scroll-timeline-axis: block; /* 指定滚动方向 */
    }
    
    @keyframes slide-in {
      from {
        transform: translateX(-100%);
      }
      to {
        transform: translateX(0);
      }
    }

    在这个例子中,.container是一个可以垂直滚动的容器,.element的动画会随着.container的滚动而播放。 滚动.container的滚动条,.element就会从左边滑入。

  • animation-timeline

    这个属性用来指定动画的时间线。 默认值是auto,表示使用传统的基于时间的动画。 如果你想使用滚动时间线,就要把它的值设置为scroll-timeline或者一个自定义的时间线名称。

    .element {
      animation-name: fade-in;
      animation-duration: 1s;
      animation-timeline: my-scroll-timeline; /* 使用自定义的时间线名称 */
    }
    
    @scroll-timeline my-scroll-timeline {
      source: .container;
      orientation: block;
    }
    
    @keyframes fade-in {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }

    在这个例子中,我们使用@scroll-timeline规则定义了一个名为my-scroll-timeline的时间线,然后把.elementanimation-timeline属性设置为my-scroll-timeline

  • 简写方式

    为了方便,你也可以使用简写方式来设置滚动时间线:

    .element {
      animation: slide-in 1s scroll-timeline .container block; /* 简写方式 */
    }
    
    @keyframes slide-in {
      from {
        transform: translateX(-100%);
      }
      to {
        transform: translateX(0);
      }
    }

    这个简写方式的顺序是:animation-name, animation-duration, animation-timeline, scroll-timeline-source, scroll-timeline-axis

第三部分: View Timeline: 让动画跟着元素可见性“起舞”

View Timeline和Scroll Timeline类似,但是它不是根据滚动条的位置来驱动动画,而是根据元素在视口中的可见性来驱动动画。 简单来说,就是元素进入视口,动画就开始播放;元素离开视口,动画就停止播放。

  • view-timeline-axisview-timeline-inset

    要使用View Timeline,你需要告诉浏览器,你要用哪个轴来判断元素的可见性,以及元素在视口中的插入距离。 这就要用到view-timeline-axisview-timeline-inset这两个属性。

    • view-timeline-axis: 指定观察的轴。 可以是block(垂直方向)、inline(水平方向)、vertical(垂直方向,效果同block)或者horizontal(水平方向,效果同inline)。
    • view-timeline-inset: 指定视口插入距离。 可以是一个长度值或者百分比,表示在计算元素可见性时,视口需要缩小的距离。
    .element {
      animation-name: fade-in;
      animation-duration: 1s;
      animation-timeline: view-timeline; /* 启用视图时间线 */
      view-timeline-axis: block; /* 指定观察的轴 */
      view-timeline-inset: 20%; /* 指定视口插入距离 */
    }
    
    @keyframes fade-in {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }

    在这个例子中,.element的动画会随着它在垂直方向上的可见性而播放。 当.element进入视口20%时,动画就开始播放;当.element离开视口20%时,动画就停止播放。

  • animation-timeline

    和Scroll Timeline一样,这个属性用来指定动画的时间线。 如果你想使用视图时间线,就要把它的值设置为view-timeline或者一个自定义的时间线名称。

    .element {
      animation-name: slide-in;
      animation-duration: 1s;
      animation-timeline: my-view-timeline; /* 使用自定义的时间线名称 */
    }
    
    @view-timeline my-view-timeline {
      subject: self; /* 观察当前元素 */
      axis: block;
      inset: auto; /* 默认值,不缩放视口 */
    }
    
    @keyframes slide-in {
      from {
        transform: translateX(-100%);
      }
      to {
        transform: translateX(0);
      }
    }

    在这个例子中,我们使用@view-timeline规则定义了一个名为my-view-timeline的时间线,然后把.elementanimation-timeline属性设置为my-view-timelinesubject: self 表示观察自身, 也可以设置为其他的CSS选择器。

  • 简写方式

    同样,你也可以使用简写方式来设置视图时间线:

    .element {
      animation: fade-in 1s view-timeline block 20%; /* 简写方式 */
    }
    
    @keyframes fade-in {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }

    这个简写方式的顺序是:animation-name, animation-duration, animation-timeline, view-timeline-axis, view-timeline-inset

第四部分: view-transition-name: 页面跳转的丝滑小技巧

view-transition-name是另一个CSS属性,它允许你在页面跳转时创建平滑的过渡动画。 这个属性主要用于单页面应用(SPA),可以让你在不同页面之间切换时,避免突兀的闪烁,让用户体验更加流畅。

  • 基本用法

    要使用view-transition-name,首先需要在两个页面上,给需要进行过渡的元素设置相同的view-transition-name

    <!-- page1.html -->
    <img src="image.jpg" style="view-transition-name: hero-image;">
    
    <!-- page2.html -->
    <img src="image.jpg" style="view-transition-name: hero-image;">

    然后,在JavaScript中,使用document.startViewTransition API来启动过渡动画。

    // 触发页面跳转的函数
    function navigate(url) {
      if (!document.startViewTransition) {
        // 如果浏览器不支持,直接跳转
        location.href = url;
        return;
      }
    
      // 启动过渡动画
      document.startViewTransition(() => {
        // 更新DOM
        location.href = url;
      });
    }

    navigate函数被调用时,浏览器会创建一个视图过渡,并执行回调函数。 在回调函数中,你可以更新DOM,例如,跳转到新的页面。 浏览器会自动创建过渡动画,让用户感觉页面切换非常平滑。

  • 自定义过渡动画

    你可以使用CSS来定制过渡动画。 例如,你可以改变过渡的持续时间、缓动函数和动画效果。

    ::view-transition-old(hero-image),
    ::view-transition-new(hero-image) {
      animation-duration: 0.5s;
      animation-timing-function: ease-in-out;
    }
    
    ::view-transition-old(hero-image) {
      transform: scale(1);
      opacity: 1;
    }
    
    ::view-transition-new(hero-image) {
      transform: scale(1.2);
      opacity: 0;
    }

    在这个例子中,我们使用::view-transition-old::view-transition-new伪元素来选择过渡前后的元素,并设置了不同的动画效果。

第五部分: 兼容性与未来展望

虽然Scroll Timeline和View Timeline非常强大,但是它们的兼容性还不是很好。 截至目前(2024年),只有Chrome和Edge等少数浏览器支持这些特性。

特性 Chrome Firefox Safari Edge
Scroll Timeline 支持 不支持 不支持 支持
View Timeline 支持 不支持 不支持 支持
view-transition-name 支持 不支持 支持 (部分) 支持

但是,随着Web技术的不断发展,相信越来越多的浏览器会支持这些特性。 未来,Scroll Timeline和View Timeline将会成为CSS动画的重要组成部分,为我们带来更加丰富和有趣的Web体验。

第六部分: 实际应用场景

说了这么多,咱们来聊聊Scroll Timeline和View Timeline的实际应用场景。

  • 视差滚动效果

    视差滚动效果是指让不同的元素以不同的速度滚动,从而营造出一种立体的视觉效果。 使用Scroll Timeline,可以很容易地实现视差滚动效果。

    <div class="container">
      <div class="background"></div>
      <div class="foreground"></div>
    </div>
    .container {
      position: relative;
      height: 500px;
      overflow-y: scroll;
    }
    
    .background {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-image: url('background.jpg');
      background-size: cover;
      transform-origin: top center;
      animation: parallax-background 1s linear forwards;
      animation-timeline: scroll-timeline;
      scroll-timeline-source: .container;
      scroll-timeline-axis: block;
    }
    
    .foreground {
      position: relative;
      z-index: 1;
      padding: 50px;
      background-color: rgba(255, 255, 255, 0.8);
    }
    
    @keyframes parallax-background {
      from {
        transform: translateY(0);
      }
      to {
        transform: translateY(-20vh); /* 背景向上移动20vh */
      }
    }

    在这个例子中,背景图片会以比前景内容慢的速度滚动,从而营造出视差滚动效果。

  • 滚动指示器

    滚动指示器可以显示当前滚动的位置,让用户知道还有多少内容没有浏览。 使用Scroll Timeline,可以很容易地实现滚动指示器。

    <div class="container">
      <div class="indicator"></div>
      <div class="content">
        <!-- 内容 -->
      </div>
    </div>
    .container {
      position: relative;
      height: 300px;
      overflow-y: scroll;
    }
    
    .indicator {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 5px;
      background-color: red;
      transform-origin: top left;
      animation: scroll-indicator 1s linear forwards;
      animation-timeline: scroll-timeline;
      scroll-timeline-source: .container;
      scroll-timeline-axis: block;
    }
    
    @keyframes scroll-indicator {
      from {
        transform: scaleX(0);
      }
      to {
        transform: scaleX(1);
      }
    }

    在这个例子中,滚动指示器会随着滚动条的滚动而变长,显示当前滚动的位置。

  • 元素进入视口动画

    当元素进入视口时,播放一个动画,可以吸引用户的注意力。 使用View Timeline,可以很容易地实现元素进入视口动画。

    <div class="element">
      <!-- 内容 -->
    </div>
    .element {
      opacity: 0;
      transform: translateY(50px);
      animation: fade-in-up 1s ease-out forwards;
      animation-timeline: view-timeline;
      view-timeline-axis: block;
    }
    
    @keyframes fade-in-up {
      from {
        opacity: 0;
        transform: translateY(50px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    在这个例子中,当元素进入视口时,它会从下方滑入,并逐渐显示出来。

总结:

Scroll Timeline和View Timeline是CSS动画的新方向,它们可以让你创建更加互动和有趣的Web体验。 虽然它们的兼容性还不是很好,但是相信随着Web技术的不断发展,它们将会得到广泛的应用。 各位靓仔靓女们,赶紧学起来,成为CSS动画界最靓的仔!

好了,今天的讲座就到这里, 感谢大家的聆听! 下课!

发表回复

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