使用CSS新特性 animation-timeline 实现 Scroll-driven Animations

favicon.png

内含实验性功能,目前仅 Chrome Canary (115以上)版本浏览器支持此特性

前言

Scroll-driven animations 顾名思义,就是由滚动驱动的动画,是一种常见的交互模式,在提升网站的用户体验方面,扮演着非常重要的角色,其应用场景比较广泛,例如:

  • 网站导航栏根据滚动条向下滚动的进度逐步缩小尺寸、最终固定尺寸和位置
  • TOC根据滚动位置高亮显示
  • 容器边缘显示含义为”滚动查看更多“的阴影效果

通常,我们需要利用JavaScript监听容器的 scroll 事件,并且拿到 scrollTop 等值来进行一系列的计算。这样做比较复杂,而且频繁获取 scrollTop 的值会因为频繁的回流重绘导致页面卡顿,动画不流畅的问题。

有没有一种更简单、高效率的方式来实现呢?当然有,我们先来看一个 Demo,演示一下效果。

Demo

效果图:
GIF 2023-6-29 11-49-20.gif

体验链接(请使用 Chrome Canary (115以上)版本):
codesandbox.io/s/scroll-dr…

可以看到,封面图随着页面滚动在逐渐缩小,并最终固定在顶部。
以上这个Demo就是纯CSS实现,没有使用任何JavaScript,接下来让我们一起看看是怎么实现的。

实现方式

animation-timeline

实现Demo效果的关键属性就是: animation-timeline(这是一个实验性的功能)

默认情况下,CSS动画运行都是使用的 DocumentTimeline,简单来说就是页面加载完成后就开始运行,@keyframes内所定义的进度是跟着自然时间走的。

Scroll-driven Animation Spec 定义了两种新的 timeline,可以指定动画在元素滚动条滚动时运行,@keyframes的进度也就跟着滚动进度进行。

  • Scroll Progress Timeline: 简称 scroll-timeline,代表容器已滚动的距离,从0%到100%
  • View Progress Timeline: 简称 view-timeline,代表一个在容器内的元素的相对于滚动距离的相对位置,从0%到100%

我们的 Demo 中使用的就是 scroll-timeline:

/** 部分样式代码 */
/** 定义动画过程 */
@keyframes sticky-header-move-and-size {
    from {
        background-position: 50% 0;
        height: 100vh;
        font-size: calc(4vw + 1em);
    }
    to {
        background-position: 50% 100%;
        background-color: #0b1584;
        height: 10vh;
        font-size: 2em;
    }
}

#header {
    /** 指定 animation-name、animation-timing-function、animation-fill-mode */
    animation: sticky-header-move-and-size linear forwards;
    /** 指定 timeline */
    animation-timeline: scroll(); 
    animation-range: 0vh 90vh;
}

P.S. animation-timeline 必须写在简写 animation 属性之后,不然会被重置为默认值 auto

animation-range

值得注意的是,还有一个新的属性:animation-range(这是一个实验性的功能)

这个属性定义了动画在时间轴上的附加范围的起始和结束位置,即动画将在时间轴的哪个位置开始和结束。Demo是缩写写法,还可以通过以下两个子属性来设置动画的起始和结束位置:

  • animation-start:指定动画的起始位置,可以使用百分比、时间值或关键字来表示。
  • animation-end:指定动画的结束位置,可以使用百分比、时间值或关键字来表示。

在Demo中,animation-range设置的是从 scoll-timeline 的 0vh 开始动画,直到滚动到 90vh 的时候停止。

scroll()

上一个Demo中,将 animation-timeline 的值设置为了 CSS 函数 scroll()(这是一个实验性的功能)

scroll() 函数可接受一个 <scroller> 和一个 <axis> 参数

<scroller> 参数可以接受以下值:

  • nearest:使用最近的祖先滚动容器(默认值)
  • root:使用文档视口作为滚动容器
  • self:使用元素本身作为滚动容器

<axis> 参数可以接受以下值:

  • block:使用滚动容器的滚动进度(默认值)
  • inline:使用行内滚动条的滚动进度
  • y:使用滚动容器的 y 轴上的滚动进度
  • x:使用滚动容器的 x 轴上的滚动进度

例如 scroll(root x) 表示使用最外层的x轴的滚动条的滚动进度

除了使用 scroll() 函数指定滚动容器,还可以使用 scroll-timeline 属性,将滚动容器的 scroll-timeline 赋值给 CSS 变量,然后在需要用到的地方给到 animation-timeline 属性;

下面是一个使用x轴滚动条进度展示进度条的示例:

GIF 2023-6-29 14-33-34.gif

体验链接(请使用 Chrome Canary (115以上)版本):
codesandbox.io/s/scroll-dr…

可以看到顶部的进度条跟随容器的滚动条进度变化而变化。实现的HTML结构为:

<div class="container" style="--num-images: 5;">
    <div class="pics">
        <div class="progress"></div>
        <div class="pic">Pic-1</div>
        <div class="pic">Pic-2</div>
        <div class="pic">Pic-3</div>
        <div class="pic">Pic-4</div>
        <div class="pic">Pic-5</div>
    </div>
</div>

部分CSS代码:

@keyframes progress-grow {
    to {
        transform: scaleX(1);
    }
}

.pics {
    /** 可简写为 scroll-timeline: --picx-scroll x; */
    scroll-timeline-name: --pics-scroll;
    scroll-timeline-axis: x;
}

.progress {
    animation: auto progress-grow linear forwards;
    /** 使用前面定义的 scroll-timeline */
    animation-timeline: --pics-scroll;
}

由于HTML结构、定位等原因,这里利用 scroll-timeline 属性将图片容器 .pics 的 scroll-timeline 赋值给变量 --pics-scroll,并且指定是 x 轴的滚动条;然后给进度条.progress使用,从而实现的以上效果。

总结

利用 CSS 的 animation-timeline 可以非常方便的实现一些平时需要使用 JavaScript 才能实现的效果,而且理论上性能会更好,动画更加丝滑。这对于打工人来说又提升了不少的效率,希望可以尽快稳定下来并且各个浏览器厂商都跟进实现吧。

本文仅简单介绍了 scroll-timeline 的一个小的应用,更多玩法以及 view-timeline 的使用方法,大家可以参考更多示例

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYjOdj3c' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片