• CSS动画中的贝塞尔曲线


    前言

    最近在学习CSS动画,其中动画时间函数的部分涉及到了贝塞尔曲线的相关知识。对于这部分知识,之前一直没有好好学习过,正好借着这个机会学习下。

    1. 贝塞尔曲线

    首先简单介绍下贝塞尔曲线。

    贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段节点 组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线 的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。 ——《百度百科》

    贝塞尔曲线在图形学中广泛应用,是非常重要的曲线。那么如何绘制一条贝塞尔曲线呢?

    线性曲线

    给定点P0、P1,线性贝塞尔曲线只是一条两点之间的直线。这条线由下式给出:

    B(t)=P0+(P1−P0)t=(1−t)P0+tP1,t∈[0,1]B(t) = P_0 + (P_1-P_0)t = (1-t)P_0 + tP_1, t\in[0, 1]B(t)=P0​+(P1​−P0​)t=(1−t)P0​+tP1​,t∈[0,1]

    线性贝塞尔曲线函数中的_t_会经过由P0P_0P0​至P1P_1P1​的B(t)B(t)B(t)所描述的曲线。例如当t=0.25t=0.25t=0.25时,即B(t)B(t)B(t)一条由点P0P_0P0​至P1P_1P1​径的四分之一处。就像由0至1的连续ttt,B(t)B(t)B(t)描述一条由P0P_0P0​至P1P_1P1​的直线。

    二次曲线

    二次方贝塞尔曲线的路径由给定点P0P_0P0​、P1P_1P1​、P2P_2P2​的函数B(t)B(t)B(t)追踪:

    B(t)=(1−t2)P0+2t(1−t)P1+t2P2,t∈[0,1]B(t) = (1-t^2)P_0 + 2t(1-t)P_1 + t^2P_2 , t\in[0, 1]B(t)=(1−t2)P0​+2t(1−t)P1​+t2P2​,t∈[0,1]

    为建构二次贝塞尔曲线,可以中介点Q0Q_0Q0​和Q1Q_1Q1​作为由0至1的ttt:

    • 由P0P_0P0​至P1P_1P1​的连续点Q0Q_0Q0​,描述一条线性贝塞尔曲线。
    • 由P1P_1P1​至P2P_2P2​的连续点Q1Q_1Q1​,描述一条线性贝塞尔曲线。
    • 由Q0Q_0Q0​至Q1Q_1Q1​的连续点B(t)B(t)B(t),描述一条二次贝塞尔曲线。

    此处可以进行公式推导:

    Q0(t)=(1−t)P0+tP1//由P0−P1可得Q0Q_0(t) = (1-t)P_0 + tP_1 // 由P_0-P_1可得Q_0Q0​(t)=(1−t)P0​+tP1​//由P0​−P1​可得Q0​

    Q1(t)=(1−t)P1+tP2//由P1−P2可得Q1Q_1(t) = (1-t)P_1 + tP_2 // 由P_1-P_2可得Q_1Q1​(t)=(1−t)P1​+tP2​//由P1​−P2​可得Q1​

    B(t)=(1−t)Q0(t)+tQ1(t)=(1−t)2P0+2t(1−t)P1+t2P2B(t) = (1-t)Q_0(t) + tQ_1(t) = (1-t)^2P_0 + 2t(1-t)P_1 + t^2P_2B(t)=(1−t)Q0​(t)+tQ1​(t)=(1−t)2P0​+2t(1−t)P1​+t2P2​

    三次曲线

    P0P_0P0​、P1P_1P1​、P2P_2P2​、P3P_3P3​四个点在平面或在三维空间中定义了三次方贝塞尔曲线。曲线起始于P0P_0P0​走向P1P_1P1​,并从P2P_2P2​的方向来到P3P_3P3​。一般不会经过P1P_1P1​或P2P_2P2​;这两个点只是在那里提供方向信息。P0P_0P0​和P1P_1P1​之间的间距,决定了曲线在转而趋进P2P_2P2​之前,走向P1P_1P1​方向的“长度有多长”。

    可以利用之前的线性公式和二阶曲线公式进行推导:

    R0(t)=(1−t)2P0+2t(1−t)P1+t2P2//由P0−P1−P2可得R0R_0(t) =(1-t)^2P_0 + 2t(1-t)P_1 + t^2P_2 //由P_0-P_1-P_2可得R_0R0​(t)=(1−t)2P0​+2t(1−t)P1​+t2P2​//由P0​−P1​−P2​可得R0​

    R1(t)=(1−t)2P1+2t(1−t)P2+t2P3//由P1−P2−P3可得R1R_1(t) =(1-t)^2P_1 + 2t(1-t)P_2 + t^2P_3 //由P_1-P_2-P_3可得R_1R1​(t)=(1−t)2P1​+2t(1−t)P2​+t2P3​//由P1​−P2​−P3​可得R1​

    B(t)=(1−t)R0(t)+tR1(t)=P0(1−t)3+3P1t(1−t)2+3P2t2(1−t)+P3t3,t∈[0,1]B(t) = (1-t)R_0(t) + tR_1(t) = P_0(1-t)^3 + 3P_1t(1-t)^2 + 3P_2t2(1-t)+P_3t3, t\in[0,1]B(t)=(1−t)R0​(t)+tR1​(t)=P0​(1−t)3+3P1​t(1−t)2+3P2​t2(1−t)+P3​t3,t∈[0,1]

    2. CSS中的贝塞尔曲线

    在CSS中,应用到贝塞尔曲线的属性主要有transitionanimation

    transition中有 transition-timing-function ,animation中有 animation-timing-function

    这两个属性类型相同,包含一个或多个类型的值。语法如下:

    #
    where 
     = linear |  | 
    
    where 
     = ease | ease-in | ease-out | ease-in-out | cubic-bezier(, , , )
     = step-start | step-end | steps([, ]?)
    
    where 
     = jump-start | jump-end | jump-none | jump-both | start | end 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    其中我们重点关注类型。可以看到该类型有五个值:

    • ease
    • ease-in
    • ease-out
    • ease-in-out
    • cubic-bezier(, , , )

    前四个关键字都是简写,最后一个则是可以通过cubic-bezier()函数生成自定义的贝塞尔曲线。

    cubic-bezier()

    cubic-bezier()函数定义了一个三次贝塞尔曲线。三次贝塞尔曲线通过四个点P0P_0P0​、P1P_1P1​、P2P_2P2​和P3P_3P3​来定义。P0P_0P0​和P3P_3P3​是曲线的起点和终点,在CSS中起点和终点都是固定的,P0P_0P0​是(0,0)(0, 0)(0,0),表示初始时间或位置以及初始状态,P3P_3P3​是(1,1)(1, 1)(1,1)表示最终时间或位置以及最终状态。

    语法如下:

    cubic-bezier(x1, y1, x2, y2) 
    
    • 1

    x1x_1x1​和y1y_1y1​定义了P1P_1P1​点的横纵坐标,x2x_2x2​和y2y_2y2​定义了P2P_2P2​点的横纵坐标。其中x1x_1x1​和x2x_2x2​的范围必须在[0,1][0,1][0,1]区间内,否则这个曲线就是无效的。

    CSS中如果声明了无效的三次贝塞尔曲线,那么整个属性的都声明都会被无视。

    上图所示为cubic-bezier(0.075, 0.75, 0.875, 0.36)声明的曲线。

    ease

    ease关键字等同于cubic-bezier(0.25, 0.1, 0.25, 1.0),特点是曲线刚开始加速较快,结束时平稳。

    ease-in

    ease-in关键字等同于cubic-bezier(0.42, 0.0, 1.0, 1.0),特点是曲线刚开始较为平稳,结束时加速剧烈。

    ease-out

    ease-out关键字等同于cubic-bezier(0.0, 0.0, 0.58, 1.0),特点是曲线开始就突然加速,结束时平稳减速。

    ease-in-out

    ease-in-out关键字等同于cubic-bezier(0.42, 0.0, 0.58, 1.0)。特点是曲线开始时加速缓慢平稳,表现和ease-in相同;结束时缓慢平稳减速,表现和ease-out相同。

    3. 贝塞尔曲线的应用

    在CSS动画中,贝塞尔曲线的横坐标代表时间比率,纵坐标代表输出比率。

    所以在某个时间点的斜率就代表动画的运动速度,曲线越陡峭,速度越快;曲线越平缓,速度则越慢。我们可以通过自定义曲线来做不同的运动动画。

    cubic-bezier.com/ 这个网站可以帮助我们快速生成自定义的贝塞尔曲线,非常的实用:

    比较经典的例子是,将参考点P1P_1P1​设置在第四象限,让曲线先向下走再向上走:

    利用这样的特殊的贝塞尔曲线,可以生成具有回弹效果的运动轨迹:

    .circle {position: relative;left: 100px;width: 100px;height: 100px;border-radius: 50%;background: deepskyblue;animation: jump 3s cubic-bezier(.6,-0.47,.63,1) forwards;
    }
    @keyframes jump {0% {transform: translateX(0);}100% {transform: translateX(300px);}
    } 
    
    • 1
    • 2
    • 3
    • 4

    效果如下:

    也可以为opacity属性添加动画,制作出先显示,再隐藏,再显示的动画:

    .visible {position: relative;top: 100px;width: 100px;height: 100px;background: black;animation: visible 5s cubic-bezier(.14,.33,.16,-0.88) both;
    }
    @keyframes visible {0% {opacity: 0;}100% {opacity: 1;}
    } 
    
    • 1
    • 2
    • 3
    • 4

    效果如下:

    总结

    本文介绍了线性贝塞尔曲线、二次贝塞尔曲线以及三次贝塞尔曲线,没有介绍高阶贝塞尔曲线是因为在CSS中只用到cubic-bezier()函数,也就是三次贝塞尔曲线。在CSS transitionanimation中使用贝塞尔曲线可以制作多种多样的缓动动画。

    除了CSS动画,在图形绘制中也经常使用贝塞尔曲线,多一些了解对于在日常的开发也会有很多的帮助,大家不妨多多尝试~

  • 相关阅读:
    adb卸载系统应用
    【web实战-业务逻辑】评论点赞逻辑
    【C++初阶(二)】缺省参数&函数重载
    都知道0.1+0.2 = 0.30000000000000004,那要怎么让它等于0.3
    分布式搜索引擎Elasticsearch基础入门学习
    游戏黑卡代充36技术及库存系统案例分析
    【Python编程】八、Python函数详解
    安卓多个listView拖动数据交换位置和拖动
    nacos不同局域网如何相互调用?nacos微服务云开发,远程联调部署,内网穿透,frp部署
    Ubuntu 20.04.5安装无线网卡RTL8821CE驱动
  • 原文地址:https://blog.csdn.net/web2022050903/article/details/126086900