首页 > 其他分享 >【动画进阶】当路径动画遇到滚动驱动!

【动画进阶】当路径动画遇到滚动驱动!

时间:2023-09-14 10:36:50浏览次数:36  
标签:动画 滚动 进阶 路径 offset path CSS

我的小册 《CSS 技术揭秘与实战通关》上线了,想了解更多有趣、进阶、系统化的 CSS 内容,可以猛击 - LINK

本文,我们将一起利用纯 CSS,实现如下这么个酷炫的效果:

在一年前,我介绍了 CSS 中非常新奇有趣的一个新特性 -- @scroll-timeline革命性创新,动画杀手锏 @scroll-timeline

利用这个新特性,我们可以轻松的将原本基于时间控制的动画效果,交给页面的滚动特性进行控制,像是这样:

只是,该特性由于诸多原因,遭到了规范废弃。

然而,时隔一年半,规范带着新的 animation-timeline 王者回归!我们可以将其简单理解为:Scroll-driven Animations(滚动驱动动画)

什么是滚动驱动动画(Scroll-driven Animations)?

OK,我们通过一个例子,快速上手(回忆)滚动驱动动画。

我们来实现这么一个滚动进度指示器效果:

bg0.gif

注意看 GIF 图的上方,有一个黄色进度条,可以通过滚动,改变黄色进度条的进度状态。这个也就是我们说的滚动指示器效果。

在之前,这个效果利用纯 CSS 是不太好实现的,但是有了 animation-timeline 之后,一切都将变得非常轻松。

假设我们有如下结构:

<div id="g-container">
    <h1>不可思议的纯 CSS 进度条效果</h1>
    <p>OK,继续....../p>
    // ...
</div>
body {
    overflow: scroll;
}
#g-container {
    width: 100vw;
}

其中,#g-container 有非常多的内容,其长度远远超过 100vh,也就是一个屏幕的高度。并且,body 是设置了 overflow: scroll 的。因此,整个页面是可以进行滚动的:

bg3.gif

好,接下来,我们需要加上进度条,实现的方式有非常多种,这里我通过给 #g-container 添加一个伪元素,将进度条的效果设置给这个伪元素,代码也非常简单:

#g-container::before {
    content: "";
    position: fixed;
    height: 7px;
    left: 0;
    top: 0;
    right: 0;
    background: #ffc107;
    animation: scale 3s linear infinite;
    transform-origin: 0 50%;
}

@keyframes scale {
    0% {
        transform: scaleX(0);
    }
    100% {
        transform: scaleX(1);
    }
}

这里,利用元素的缩放,从 transform: scaleX(0)transform: scaleX(1) 的变化,实现了进度条的动画效果。

只不过,目前是一个无限动画,一次动画效果持续 3 秒 -- animation: scale 3s linear infinite

bg4.gif

好,铺垫到这里,接下来终于要轮到 animation-timeline 登场了。

上述的动画效果,目前是由时间进行控制的,持续时长为 3s,而我们的目标,就是利用滚动的效果控制整个动画。

我们只需要简单的改造一下代码:

#g-container::before {
    // ...
    animation: scale 3s linear;
    animation-timeline: scroll(root);
    transform-origin: 0 50%;
}

这里,我们仅仅加了一句 animation-timeline: scroll(root),表示利用滚动进行元素的动画控制,并且利用的是 root 元素的滚动,也就是 body 元素的滚动进行控制。

这样,我们就轻松的实现了一个滚动指示器效果:

bg0.gif

完整的代码,你可以戳这里:CodePen Demo -- 使用 scroll-animation 实现滚动指示器进度条

当然,整个滚动驱动动画(Scroll-driven Animations)的内容还是非常多的,本文不对基础语法做过多展开,大家可以通过下面两个途径,进一步了解新语法:

  1. MDN 文档 -- animation-timeline
  2. XboxYan 大佬的 CSS 滚动驱动动画终于正式支持了~

借用 XboxYan 文章中的一幅图:

image.png

motion-path 运动路径动画

好,到目前位置,我们都还在铺垫内容,本文的核心是当路径动画遇到滚动驱动

那么,了解完滚动驱动动画之后,我们再来了解一下,什么是运动路径动画 -- motion-path

motion-path 在之前,也有过系统的介绍 -- 探秘神奇的运动路径动画 Motion Path

什么是 CSS Motion Path 运动路径?利用这个规范规定的属性,我们可以控制元素按照特定的路径进行位置变换的动画。并且,这个路径可以是非常复杂的一条路径。

初窥 motion-path

CSS Motion Path 规范主要包含以下几个属性:

  • offset-path:接收一个 SVG 路径(与 SVG 的path、CSS 中的 clip-path 类似),指定运动的几何路径
  • offset-distance:控制当前元素基于 offset-path 运动的距离
  • offset-position:指定 offset-path 的初始位置
  • offset-anchor:定义沿 offset-path 定位的元素的锚点。 这个也算好理解,运动的元素可能不是一个点,那么就需要指定元素中的哪个点附着在路径上进行运动
  • offset-rotate:定义沿 offset-path 定位时元素的方向,说人话就是运动过程中元素的角度朝向

下面,我们使用 Motion Path 实现一个简单的直线位移动画。

<div>
div {
    width: 60px;
    height: 60px;
    background: linear-gradient(#fc0, #f0c);
    offset-path: path("M 0 0 L 100 100");
    offset-rotate: 0deg;
    animation: move 2000ms infinite alternate ease-in-out;
}
@keyframes move {
    0% {
        offset-distance: 0%;
    }
    100% {
        offset-distance: 100%;
    }
}

offset-path 接收一个 SVG 的 path 路径,这里我们的路径内容是一条自定义路径 path("M 0 0 L 100 100"),翻译过来就是从 0 0 点运动到 100px 100px 点。

offset-path 接收一个 SVG 路径,指定运动的几何路径。与 SVG 的path、CSS 中的 clip-path 类似,对于这个 SVG Path 还不太了解的可以戳这里先了解下 SVG 路径内容:SVG 路径

我们会得到如下结果:

通过控制元素的 offset-distance0% 变化到 100% 进行元素的路径动画。

当然,上述的动画是最基本的,我可以充分利用 path 的特性,增加多个中间关键帧,稍微改造下上述代码:

div {
    // 只改变运动路径,其他保持一致
    offset-path: path("M 0 0 L 100 0 L 200 0 L 300 100 L 400 0 L 500 100 L 600 0 L 700 100 L 800 0");
    animation: move 2000ms infinite alternate linear;
}
@keyframes move {
    0% {
        offset-distance: 0%;
    }
    100% {
        offset-distance: 100%;
    }
}

这里最主要还是运用了 path 中的 L 指令,得到了如下图这样一条直线路径:

最终的效果如下,与利用 transform: translate() 添加多个关键帧类似:

完整的 Demo 你可以戳这里:CodePen Demo -- CSS Motion Path Demo

曲线路径动画

上面的运动轨迹都是由直线构成,下面我们看看如何使用 CSS Motion Path 实现曲线路径动画。

其实原理还是一模一样,只需要在 offset-path: path() 中添加曲线相关的路径即可。

在 SVG 的 Path 中,我们取其中一种绘制曲线的方法 -- 贝塞尔曲线,譬如下述这条 path,其中的 path 为 d="M 10 80 C 80 10, 130 10, 190 80 S 300 150, 360 80"

<svg width="400" height="160" xmlns="http://www.w3.org/2000/svg">
  <path d="M 10 80 C 80 10, 130 10, 190 80 S 300 150, 360 80" stroke="black" fill="transparent"/>
</svg>

对应这样一条连续的贝塞尔曲线:

将对应的路径应用在 offset-path: path 中:

<div>
div:nth-child(2) {
    width: 40px;
    height: 40px;
    background: linear-gradient(#fc0, #f0c);
    offset-path: path('M 10 80 C 80 10, 130 10, 190 80 S 300 150, 360 80');
}
@keyframes move {
    0% {
        offset-distance: 0%;
    }
    100% {
        offset-distance: 100%;
    }
}

可以得到如下运动效果:

可以看到,元素是沿着贝塞尔曲线的路径进行运动的,并且,由于这次没有限制死 offset-rotate,元素的朝向也是跟随路径的朝向一直变化的。(可以联想成开车的时候,车头一直跟随道路会进行变化的,带动整个车身的角度变化)

完整的 Demo 你可以戳这里:CodePen Demo -- CSS Motion Path Demo

Amazing!路径动画配合滚动驱动

好,终于,到这里,你应该已经大致了解了什么是路径动画 motion-path,什么是滚动驱动 scroll-driven

我们可以尝试把这两个东西组合在一起。

假设,我们有这么个 HTML 结构:

<div class="g-container">
    <div class="ele"></div>
</div>
body {
    width: 100%;
    height: 100%;
    background: conic-gradient(
        #fff,
        #fff 90deg,
        #ddd 90deg,
        #ddd 180deg,
        #fff 180deg,
        #fff 270deg,
        #ddd 270deg
    );
    background-size: 50px 50px;
}
.g-container {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, 0);
    width: 700px;
    height: 2000px;
}
.ele {
    position: absolute;
    width: 40px;
    height: 40px;
    clip-path: polygon(0 0, 100% 50%, 0 100%);
    background: linear-gradient(270deg, #65d060, #0887ec);
}

简单解释一下:

  1. 为了方便理解,我把 body 的背景设置成了格子背景
  2. .g-container 是一个远比屏幕高度高的容器,方便整个页面进行滚动
  3. .ele 是一个小三角形

目前,整个页面是这样的:

image.png

下面,我们给 .ele设置一个 offset-path 路径:

.ele {
    position: absolute;
    width: 40px;
    height: 40px;
    clip-path: polygon(0 0, 100% 50%, 0 100%);
    background: linear-gradient(270deg, #65d060, #0887ec);
    offset-path: path("M 350 40 C 1000 1000, -350 1000, 350 1960");
    animation: move 4s linear infinite;
}

@keyframes move {
    0% {
        offset-distance: 0%;
    }
    50% {
        transform: scale(2.5);
    }
    100% {
        offset-distance: 100%;
    }
}

其中的核心就是 offset-path: path("M 350 40 C 1000 1000, -350 1000, 350 1960") 这里面,有一个利用 3 次贝塞尔曲线画出来的路径。

并且,我们给它加上了 offset-distance: 0offset-distance: 100% 的动画效果,目前,整个效果是这样的:

bg5.gif

可以看到,小三角形,按照特定的路径在进行运动。

为了更好的理解这个动画,我们可以利用 SVG,把这个运动的路径给画出来:

<div class="g-container">
    <svg class="g-svg" width="400" height="160" xmlns="http://www.w3.org/2000/svg">
        <path id="svgpath" d="M 350 40 C 1000 1000, -350 1000, 350 1960" stroke="black" fill="transparent" />
    </svg>
    <div class="ele"></div>
</div>
.g-svg {
    position: absolute;
    top: 0;
    left: 50%;
    width: 700px;
    height: 2000px;
    transform: translate(-50%, 0);
}
#svgpath {
    stroke: #9bc9de;
    stroke-width: 3px;
    stroke-dasharray: 2108, 2108;
    animation: lineMove 4s linear;
}
@keyframes lineMove {
    0% {
        stroke-dashoffset: 2108;
    }
    100% {
        stroke-dashoffset: 0;
    }
}

我们利用 SVG 路径,成功的将运动的路径绘制了出来,并且,利用 stroke-dasharraystroke-dashoffset,实现了一条线条动画,控制它和小三角形的 motion-path 动画保持一致。

要看懂 stroke-dasharraystroke-dashoffset 实现的线条动画,可能需要翻阅:【Web动画】SVG 线条动画入门

这样,现在,我们就得到了这么一个动画效果:

bg6.gif

到这里,其实还没有运用上滚动驱动,现在,我们把上述经由时间控制的动画效果,交给页面的滚动。

简单改造上述 CSS 代码:

.ele {
    position: absolute;
    width: 40px;
    height: 40px;
    clip-path: polygon(0 0, 100% 50%, 0 100%);
    offset-path: path("M 350 40 C 1000 1000, -350 1000, 350 1960");
    background: linear-gradient(270deg, #65d060, #0887ec);
    animation: move 4s linear;
    animation-timeline: scroll(root);
}

#svgpath {
    stroke: #9bc9de;
    stroke-width: 3px;
    stroke-dasharray: 2108, 2108;
    animation: lineMove 4s linear;
    animation-timeline: scroll(root);
}

改动比较简单:

  1. 去掉两个动画效果的 infinite 关键字
  2. 添加上 animation-timeline: scroll(root)

此时,我们就可以利用页面的滚动,控制整个动画效果:

bg7.gif

完整的 DEMO,你可以戳这里:CodePen Demo -- Scroll Driven & motion path & SVG stroke-dasharray Demo

在灵活掌握了上述内容后,我们就可以利用路径动画及滚动驱动创造出各种妙趣横生的动画效果!

下面是我综合利用各种技巧,实现的一个纯 CSS 滚动动画效果,感受一下:

上述案例中,除了本文介绍的所有内容外,使用了本文没有提及的滚动驱动 API 中的 animation-range以及 CSS 与布局相关的 shape-outside 属性,如果不太了解这两个属性,需要自行补充相关知识。

Amazing!是不是非常的酷炫有意思,到今天,这种效果已经是纯 CSS 代码就能实现完成的了!

完整的代码基于上述的 DEMO 进行扩展得到,就不贴出来了,感兴趣的可以猛戳:CodePen Demo - CSS Scroll Driven

Can i Use - CSS Scroll Driven

来看看 CSS Scroll Driven 相关的 API 目前的兼容性如何?截止至 2023-09-09,基于 Can i Use - Animation-timeline 的兼容性如下:

可以看到 animation-timeline 已经从 Chrome 115 版本正式得到支持,并且其它浏览器也已经开始大力跟进,让我们给时间一点时间,相信很快 CSS Scroll Driven 会更多的应用于生产环境,创造出各种以往需要借助 JavaScript 才能实现的动画。

而当路径动画遇到滚动驱动,势必会创造出各种妙趣横生的效果,更多有趣的效果组合等待我们去探索发现。

最后

好了,本文到此结束,希望对你有所收获。

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

标签:动画,滚动,进阶,路径,offset,path,CSS
From: https://www.cnblogs.com/coco1s/p/17701807.html

相关文章

  • Python学习笔记-Python函数进阶
    函数多返回值思考如果一个函数有两个return,程序如何执行?例如:defreturn_num():return1return2result=return_num()print(result)上面代码只执行了第一个return,因为retrun可以退出当前函数,导致return下方的代码不执行。多个返回值如果一个函数要有多个返回值,书写方式示......
  • 【小沐学Unity3d】3ds Max 骨骼动画制作(Physique 修改器)
    1、简介官方网址:https://help.autodesk.com/view/3DSMAX/2018/CHS/?guid=GUID-22E831B0-8B6B-4759-B5FB-4B86B6276A00使用Physique修改器可将蒙皮附加到骨骼结构上,比如Biped。蒙皮是一个3dsMax对象:它可以是任何可变形的、基于顶点的对象,如网格、面片或图形。当以附加蒙皮......
  • Vue H5 Swiper 动画
    简介及使用教程VueH5Swiper是一个H5移动滑块组件,适用于H5应用程序,轻量。安装Npmnpmivue-h5-swiperYarnyarnaddvue-h5-swiper使用引入import{Swiper,SwiperItem}from'vue-h5-swiper';注册exportdefault{components:{Swiper,Swiper......
  • C++算法进阶系列之倍增算法解决求幂运算
    1.引言学习倍增算法,先了解什么是倍增以及倍增算法的优势。如果面前有一堆石子,要求计算出石子的总数量。这是一个简单的数数问题,可以:一颗石子一颗石子的数。两颗石子两颗石子的数。三颗石子三颗石子的数。或者更多颗石子更多颗石子的数……在石子很多的情况下,每一次选择更......
  • Unity 游戏开发、02 基础篇 | 知识补充、简单使用动画、动画状态机
    前置笔记(由浅入深)Unity游戏开发、01基础篇2场景操作3D场景Q手型工具(鼠标中键):上下左右移动场景ALT+鼠标左键:以视图为中心旋转鼠标右键:以观察者为中心旋转SHIFT+Gizmo方块:Y轴归位物体节点+F:观察者定位至物体窗口布局3D项目一般窗口布局如下3全局光照全......
  • 【小沐学Unity3d】3ds Max 骨骼动画制作(Mixamo )
    1、简介官网地址:https://www.mixamo.com/#/使用Mixamo上传和装配AdobeFuseCC3D人物、自定义3D人物,或者利用Mixamo库中的人物开始操作。<fontcolor=blue>Mixamo支持3种文件格式上载:FBX,OBJ,ZIP。确保FBX文件的“嵌入媒体”已打开,以上传纹理。OBJ文件不包含纹理,使字......
  • 基于vue制作的动画组件loading起来
    ......
  • day七-Python之路 - 面向对象学习编程进阶
    Python之路,Day7-面向对象编程进阶 本节内容:面向对象高级语法部分经典类vs新式类静态方法、类方法、属性方法类的特殊方法反射异常处理Socket开发基础作业:开发一个支持多用户在线的FTP程序面向对象高级语法部分经典类vs新式类把下面代码用python2......
  • Animation动画——ObjectAnimator基本使用
    ObjectAnimator是ValueAnimator的子类,他本身就已经包含了时间引擎和值计算,所以它拥有为对象的某个属性设置动画的功能。这使得为任何对象设置动画更加的容易。你不再需要实现ValueAnimator.AnimatorUpdateListener接口,因为ObjectAnimator动画自己会自动更新相应的属性值。ObjectAn......
  • FFmpeg进阶: 音频滤镜大全
    在做音频处理模块的时候,为了对声音进行优化处理,我很多时候会使用各种算法对音频进行变换,效果包括变音变调、声音降噪等等。其实FFmpeg库里的滤镜模块包含了很多有用的音频滤镜算法,这对于提升开发效率避免重复造轮子是很有帮助的。这里翻译了一下FFmpeg官方文档的所有音频滤镜的介......