FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
362 stars 39 forks source link

CSS动画之timing functions #183

Open FrankKai opened 4 years ago

FrankKai commented 4 years ago

参考资料: https://easings.net/ https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function https://en.wikipedia.org/wiki/B%C3%A9zier_curve https://github.com/hujiulong/blog/issues/1 https://en.wikibooks.org/wiki/LaTeX/Mathematics

缓动函数概览

<easing-function> easing function的意思是缓动函数。<easing-function>代表的是一个数学函数,这个数学函数描述动画期间一维值变化的速度。这让你在整个动画过程中改变动画的速度。

在三次贝塞尔曲线缓动函数子集的缓动函数通常叫做”平滑“缓动函数,因为他们能被用来使得开始和结束变得平静。他们将时间率和输出率关联,都用<number>s来表达。对于这些值,0.0代表初始状态,1.0代表结束状态。

依赖特定使用的函数,计算后的输出值在动画期间的有些时候可能比1.0大或者比0.0小。这导致动画比最终状态跑得更远,然后返回一些属性,比如left,right,这就产生了弹跳效果

image image

然而,如果输出超出了允许的范围,某些属性将限制输出。例如,一个颜色组件大于255或者小于0会被替换为255或者0。一些立方cubic-bezier()曲线有这种属性。

缓动函数的cubic-bezier()类

image

CSS支持两种缓动函数:函数三次贝塞尔曲线的子集和楼梯函数。这两种最常见的函数通常可以给定关键字引用。

cubic-bezier()定义了三次贝塞尔曲线。这些曲线是连续的,他们通常会使开始和结束变得滑动,因此通常叫做缓动函数。

一个贝塞尔曲线包含4个点。P0, P1, P2, 和P3。P0和P3是起点(0,0)和终点(1,1),在CSS中这些点是固定的,代表了时间和状态,因为坐标是比率。(在CSS中,横坐标表示时间之比,纵坐标表示输出范围之比,坐标表示输出范围之比)。

不是所有三次贝塞尔曲线都适合做缓动函数,因为不是所有的都是数学函数;例如,给定横坐标为0或1的曲线。根据CSS的定义,固定了P0和P3,三次贝塞尔曲线是一个函数,因此,当且仅当P1和P2的横坐标都在[0,1]范围内时,三次贝塞尔曲线是有效的。

P1,P2如果在[0, 1]范围外的话,可能会导致弹珠副作用。

当你指定了一个无效的cubic-bezier曲线,CSS会忽略这个属性。

语法

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

x1,y1,x2,y2代表的是横纵坐标,x1和x2必须在0到1之间,y1,y2可以超出这个范围。

例子

有效例子

/*准确的贝塞尔曲线值都在0和1之间 */
cubic-bezier(0.1, 0.7, 1.0, 0.1)
/*整数有效*/
cubic-bezier(0,0,1,1)
/*负数有弹跳效果*/
cubic-bezier(0.1, -0.6, 0.2, 0)    
/*大于1的数字也是有效的*/
cubic-bezier(0, 1.1, 0.8, 4)

无效例子

/*颜色*/
cubic-bezier(0.1, red, 1.0, green) 
/*横坐标不在[0,1]*/
cubic-bezier(2.45, 0.6, 4, 0.1)    
/*两个点必须被定义,没有默认值*/
cubic-bezier(0.3, 2.1)   
/*曲线不是时间函数*/
cubic-bezier(-1.9, 0.3, -0.2, 2.1) 

三次贝塞尔曲线方程推导过程

image

image

$B_{P_0,P_1}(t)=P_0+t(P_1-P_0)=(1-t)P_0+tP_1,  0 \leq t \leq 1 $
$B'_{P_0,P_1}(t)=P_1-P_0$

$$\begin{align*}B_{P_0,P_1,P_2}(t) & =(1-t)B_{P_0,P_1}(t)+tB_{P_1,P_2}(t) \\ &=(1-t)[(1-t)P_0+tP_1]+t[(1-t)P_1+tP_2]\\&=(1-t)^2P_0+2t(1-t)P_1+t^2P_2 \end{align*}$$
$B'_{P_0,P_1,P_2}(t)=2(1-t)(P_1-P_0)+2t(P_2-P_1)$

$$\begin{align*}B_{P_0,P_1,P_2,P_3}(t) & =(1-t)B_{P_0,P_1,P_2}(t)+tB_{P_1,P_2,P_3}(t) \\ &=(1-t)[(1-t)^2P_0+2t(1-t)P_1+t^2P_2]+t[(1-t)^2P_1+2t(1-t)P_2+t^2P_3]\\&=(1-t)^3P_0+3t(1-t)P_1+3t^2(1-t)P_2+t^3P_3 \end{align*}$$
$B'_{P_0,P_1,P_2,P_3}(t)=3(1-t)^2(P_1-P_0)+6t(1-t)(P_2-P1)+3t^2(P_3-P_2)$

微积分中一阶导数在描述物体运动时,代表的是物体的瞬时速度和加速度。 观察线性贝塞尔曲线,二阶贝塞尔曲线和三次贝塞尔曲线的一阶导数可以看出,线性的是一个常数,二阶的会随时间变化,但是变化幅度较小,三阶贝塞尔曲线就不一样了,变化很多遍。

线性贝塞尔曲线几何意义

image

线性贝塞尔曲线绘制过程:

undefined

二次贝塞尔曲线几何含义

image

二次贝塞尔曲线绘制过程:

引用一段用canvas绘制一个曲线动画——深入理解贝塞尔曲线中的解释:

选定一个0-1的t值 通过P0和P1计算出点Q0,Q0在P0 P1连成的直线上,并且length( P0, Q0 ) = length( P0, P1 ) t 同样,通过P1和P2计算出Q1,使得length( P1, Q1 ) = length( P1, P2 ) t 再重复一次这个步骤,通过Q1和Q2计算出B,使得length( Q0, B ) = length( Q0, Q1) * t。B就为当前曲线上的点

这里的length是两点间的长度。

上面的解释已经很清楚了,但是我再做一个通俗的解释: P0向P1运动,预期同时P1向P2运动。时间向前,P0和P1上产生了唯一点Q0,P1和P2上也产生唯一点Q1,Q0的坐标由length(P0,P1)t计算出,Q1的坐标由length(P1,P2)t计算得出,此时将Q0和Q1连接起来,满足公式length(Q0,B)=length(Q0,Q1)*t,从而得到为一点B。时间继续向前,得到B的运动轨迹。

三次贝塞尔曲线几何意义

image

三次贝塞尔曲线绘制过程:

三次贝塞尔曲线与二次的推导过程是一致的,只不过现在的辅助点从1个变为了2个,可以将这2个辅助点想象成2个空间,因为我们知道,3个点可以确定一个面,4个点确定的就是一个空间了,这也是将三次贝塞尔曲线称作立方贝塞尔曲线的原因。也就是说,动画使用三次贝塞尔曲线以后,模拟的不仅仅是而且空间的动画,而是三维空间的动画。

常用三次贝塞尔缓动函数的关键词

linear ease ease-in ease-in-out ease-out

linear

image 动画从开始到结束都是一个固定的速率。这个关键词在cubic-bezier中表示为cubic-bezier(0.0,0.0,1.0,1.0)

ease

image

cubic-bezier(0.25,0.1,0.25,1.0)比ease-in-out加速的快。

ease-in

image

cubic-bezier(0.42, 0.0, 1.0, 1.0)

ease-in-out

image

cubic-bezier(0.42, 0.0, 0.58, 1.0)

ease-out

cubic-bezier(0.0, 0.0, 0.58, 1.0)

知识点:其实ease-in-out是开始ease-in,结束ease-out。根据这个知识点,可以很好的理解缓动函数列表

缓动函数的steps()类

steps()函数定义了一个步长函数,它以等距步长划分输出值域。 这个阶跃函数的子类有时也称为阶梯函数。

语法

steps(number_of_steps, direction)

等距踏板的数量;连续的方向:左连续或者右连续。

steps(2, jump-start) steps(2, start) image

steps(4, jump-end) steps(4, end) image

steps(5, jump-none) image

steps(3, jump-both) image

step-start image

step-end image