thanks kirupa


当你创建一个animation或transition的动画,动画运行过程中属性发生的变化与在终止状态时发生的变化同等重要。比如,属性值随时间线性变化:

Animation Img

在这个例子里,动画看起来不会加速也不会减速。动画以固定单调的速率移动。你可以通过更多的一些属性风格变化把动画提高一个档次:

Animation Img

在这个例子中,开始时属性值变化的比较快,接近终止时变慢。

上面两个例子中,最终结果是相同的。起始状态,确定一个属性初始值。终止状态,经过指定的时延后,变为终止值。如果只在动画起始和终止状态睁开眼,而在动画运行过程中闭上眼,你看不到两个动画的区别。唯一不同的是,在动画生命过程中不同时间段属性值变化的速率,一个是线性的另一个是非线性的。

动画属性如何从初始值到终止值变化的速率有个名字。这个名字是easing function,该内容将贯穿本章始终。

Onwards!

Making Sense of Easing Functions

在前面小节中,谈到缓动函数时,两种不同颜色图表展示属性如何变化。其中一个颜色的线性缓动函数没做太多的东西。另一个颜色的非线性缓动函数,在你的动画运行后,速率减慢。在本节中,让我们转换下视角,关注于缓动函数而不去关注实际属性值的变化和时延。在该部分里,你将看到一些可爱的图表包括lines, labels, numbers和其它你在学校没有见过的东西。噢耶!

Meet the Easing Function Curve

无论是谁在什么时候谈论缓动函数,它仅是关于时间的一个图表,就是众所周知的缓动函数曲线图

Animation Img

掌握缓动函数非常重要的一部分就是怎样绘制和理解这个曲线图,那么让我们看看怎样定义该图表吧。我们需要一个羔羊(实例)来帮助我们理解。这里有一个例子。

The Example

这个例子比较简单。我们使用linear缓动函数将元素的opacity属性值线性的在2秒内从1改变到0。这可使用animation也可使用transition--这真没什么关系。

该例的曲线图是绘制时延(2秒)和opacity值,如下:

Animation Img

通过这个图表,很简单的看出,在2秒内的任意时间点opacity属性值是多少。在1秒的位置,opacity属性值为.5。在1.5秒的位置opacity属性值为.25,等等。

Visualizing Easing Functions

在这里,事情变得有趣起来。缓动函数定义属性改变的速率。给定时间点的属性值是多少 和动画属性从初始值到终止值如何改变一样不重要。意思是上面绘制的图表不是最好的。让我们扩展一下,使用百分比绘制一个缓动函数曲线图。

不使用具体的属性值和时延绘制它们,而用比率代替它们。相比于动画属性值实际变化了多少,我们使用百分比表示当前值与终止值的比率。把前面的图表转化为我们期望的图表看起来如下:

Animation Img

尽管看起来与前面的图表不同,但之前的细节仍能在这里表现出来。你需更深入一些。在这个例子里,opacity属性值从开始的1变化为结束时的0。起始状态动画完成了0%,opacity属性值是到达终止值0的0%:

Animation Img

蓝线就是开始于属性值的0%处。

当你的动画完成后,你的opacity属性值是0——即终止值。另一种说法是它需要达到100%的那个地方,动画已经完成:

Animation Img

就像你所看到的一样,蓝线的属性在100%处结束,因为它的变化是线性的,你得到的一条直线从左下角(0%,0%)到右上角(100%,100%)。

随着这个具有代表性的动画,要注意的是,在开始和结束时关注的属性实际值已不再那么重要。opacity属性值可以是0和1之间的其他值,color属性值可以是#FFFFF 和 #00000 之间的值,可以是一些正值和负值,还可以是一些更多的东西。动画可以是0.2秒的时延或者600秒的时延已不再重要。在这一点上,将全部讨论的细节放到完成的比率。最重要的是动画生命周期中任意点与最终值的比率是多少

Visualizing Easing Functions...for Real This Time!

本小节的标题含义没有太多的戏剧性。上节看到的基于百分比的图表包含缓动函数。我并没有强调它们,是因为还不是时候:

Animation Img

蓝色的曲线表示笼统的缓动函数。现在你知道了这一点,那就让我们更深入的研究这个曲线吧。

Linear Cases

对于一个线性来说,正如你刚才所看到的,最终结果就是一条直线。动画紧密的完成移动过程:

Animation Img

着重谈一下吧,任意选择一点,例如选择30%完成率的位置,表示属性值改变了多少,以及动画运行了多久。图上的映射将得出,在2秒内属性值从1改变到0,30%处表示了opacity值为0.7,用时0.6秒。这是一个比较简单的乘法运算。

在大多数情况下,你实际不需做任何乘法运算,将基于百分比类似的东西转化为实际值。你需要知道的就是看看缓动函数曲线是怎样影响你的动画的。就像这样一条直线,很清晰的看到它将如何影响你的动画。

The Awesome Non-Linear Cases

当然,不是所有的函数都像线性缓动函数那样简单。更多特殊的非线性用例,属性的变化与动画实现完成相差多少:

Animation Img

例如,看一看动画完成75%的时候所处的位置吧:

Animation Img

从图表中看到,动画完成75%并不意味着最终属性值改变了75%。而看起来更像45%。看一下缓动函数曲线,到终止前,属性值的变化率赶不上动画的完成率。意思是动画开始运行时比较缓慢,然后不断加速。不同的缓动函数所起的作用不同,一会你就将看到这些不同的缓动函数。

What You Can and Can't Do

看来理论上的学习都已经完成了。最后,在深入学习这无聊的概述之前,大致看看你在CSS缓动函数中能做什么和不能做什么。

You Always Start at 0% and End at 100%

也许你知道的最大一个限制是属性的变化过程始终是开始于0%和结束于100%。不管缓动函数在中间过程做任意东西。起始和结束状态清晰定义的属性值不能被改变:

Animation Img

这是什么意思呢?意思是缓动函数不能使你的动画开始于除初始值外的其它值。同样地,动画结束时,缓动函数也让更改你的属性为除终止值外的其它值。在起始和结束状态之间,缓动函数可以做许多不同的疯狂事情。只有这些,在起始和结束状态保持这种秩序。

There Is No Box

说到起始和结束状态之外的疯狂事件,属性值可以改变为除0%-100%之外的东西:

Animation Img

属性值超出初始值和终止值的范围是让你动画变得更真实的一个重要细节。 12 Basic Principles of Animation 中的一个称为 Follow through. Follow through描述了一个动画技术不能立刻停止下来。它会稍微超出终止值,然后返回原点。这是很有用的技术,运行中可超出0%-100%的值。

My Name is Curve...Cubic Bezier Curve!

至此,我们粗略的介绍了缓动函数。作为学习它的一部分,如用手工绘制是能接受的。现在我们来更进一步的、更精准的学习缓动函数。从更正式的缓动函数曲线开始吧。

缓动函数曲线不是简单的称为缓动函数曲线。它有一个简单的学名。它们更正式的被称为 cubic bezier curves(三次贝塞尔曲线).。当然我不会深入讨论数学上三次贝塞尔曲线的东西,这里提供足够的信息可以让你有效的用它们创建有意思的动画。

让我们开始看一下缓动函...呃...是贝塞尔曲线:

Animation Img

这个曲线不像是从马车上跌落的东西。它是用数学上曲线函数,表示它是由很多精准点组成的集合:

Animation Img

你只需要知道的是三次贝塞尔曲线由4个点创建。我已经在图上标注了那4个点,P0, P1, P2, 和 P3.。在这个图表中每个点由两个表示横纵坐标的值组成--两个值是 xy

Animation Img

我用数值而不是使用百分比来表示这些点,是因为通常很少在三次贝塞尔曲线中用到百分比。从上面的图中,很容易获取P1 和P2 的值。我仅是将这完成率和属性变化率转变为数值型。请注意这里我没有标注P0 and P3 是因为它们 在HTML的值总是 (0, 0) 和(1, 1)。

这些点的值极其重要,不仅是因为在图表中能很好的标注它们。而且这些是被指定在CSS中的值----很快你就能看到了。

Easing Functions in CSS

最后,我们不去讨论图表而转到CSS范围内。CSS属性中的两个清晰的命名为 transition-timing-functionanimation-timing-function 可以定义缓动函数。 它们的名称出卖了它们。在CSS animations里使用 animation-timing-function 在CSS transitions中使用 transition-timing-function

让我们快速看看这些时间函数各自的用武之地吧。

Easing Functions in Animations

在CSS animation中, animation-timing-function 属性被定义在两个地方。一个是animation声明的一部分:

/* shorthand */
#foo {
    animation: bobble 2s ease-in infinite;
}

/* longhand */
#somethingSomethingDarkSide {
    animation-name: deathstar;
    animation-duration: 25s;
    animation-iteration-count: 1;
    animation-timing-function: ease-out;
}

它也可被声明在单独的关键帧中:

@keyframes bobble {
    0% {
        transform: translate3d(50px, 40px, 0px);
        animation-timing-function: ease-in;
    }
    50% {
        transform: translate3d(50px, 50px, 0px);
        animation-timing-function: ease-out;
    }
    100% {
        transform: translate3d(50px, 40px, 0px);
    }
}

在animation中声明一个缓动函数,实际意思是它包括的每一个关键帧都将受这个缓动函数的影响。这与将 animation-timing-function 分别定义在每一个关键帧中没有什么不同。但这样你可以少敲一些字符。

因为级联关系,定义在关键帧中的一个缓动函数将覆盖掉animation声明的缓动函数。这是一件好理解的事,能在不同地方(关键帧)混合使用缓动函数。需要注意的最后一件事是,定义在一个关键帧中的animation-timing-function只会影响 从当前关键帧运行到下一关键帧动画过程。意思是你不能在最后一个关键帧中定义缓动函数,因为动画没有下一帧了。如果你真的给最后一帧声明了缓动函数,它会被忽略掉...你真定义它会被笑话的。

Easing Functions in Transitions

Transitions中的缓动函数比较简单些,transition-timing-function 只能被声明在transition属性中:

/* shorthand */
#bar {
    transition: transform .5s ease-in;
}

/* longhand */
#karmaKramer {
    transition-property: all;
    transition-duration: .5s;
    transition-timing-function: ease-in;
    transition-delay: .1s;
}

公平的讲,使用transition,没有第二个地方可以声明缓动函数,所以不要过多的赞美它。

Note - Default Timing Function Values

Animation或 transition中设置缓动函数是可选的。原因是任意一个animation或transition默认会有一个缓动函数值---ease。

Meet the Easing Functions / Timing Functions

现在你已经知道怎样CSS中定义缓动函数了,让我们实际看一下这些不同的缓动函数吧。你可设置的transition-timing-functionanimation-timing-function 属性值如下:

  • ease
  • linear
  • ease-in
  • ease-out
  • ease-in-out
  • step-start
  • step-end
  • steps()
  • cubic-bezier()

在接下来的几节中,我会在某种程度上解释每一个函数。

cubic-bezier()

让我们从最具有目的性的三次贝塞尔曲线函数开始吧。这个函数有4个参数,这些参数分别映射曲线中 P1 和P2 :

Animation Img

前两个参数是x和y,表示 P1点。后两个参数表示P2:

Animation Img

P0 和 P3 不用管,因为它们是固定的。如果你还记得前面内容,它们是起始点和结束点的值。完全不用管它们,确实如此。

当把这些参数放进去的时候,你的贝塞尔缓动函数看起来如下:

.foo {
    transition: transform .5s cubic-bezier(.70, .35, .41, .78);
}

从实际出发,不需要你将一些随机值放到函数中,测试一下看是不是想要结果。那简直太浪费时间了。你要做的是访问这个在线工具,来简化你的工作。

我最喜爱的在线资源是 Lea Verou's的 cubic-bezier generator

Animation Img

她的工具可让生成你想要的任意可用的缓动函数。你使用它玩三次贝塞尔曲线,预览它生成什么样的动画,并容易得到CSS中贝塞尔函数的参数值。

另一个我喜欢的网站是Matthew Lein 写的CSS Easing Animation

Animation Img

==不仅可以生成CSS内嵌缓动函数,还可生成 Robert Penner 的 easing equations,并可预览它们。

使用Lea 和Matthew 的网站,你不用尝试痛苦的摆弄三次贝塞尔定义点的值,只需键入它们的参数。

The Other Easing Functions

现在你已经知道如何定义一个 cubic-bezier() 函数,你可凭想象创建任意种类的该函数。这个函数的唯一缺点就是你必须指定创建该曲线的4个参数。上面的两个站点工具能帮你做这事,但你也可指定一些内建的缓动函数,比如ease, linear, ease-in, ease-out, 和ease-in-out.

这些内建函数提供一种快捷方式。你可使用cubic-bezier函数重定义它们。也这是,这些是非常棒的。这些cubic bezier 曲线看起来如下:

Animation Img

在上面的图表中,我单独将ease缓动函数列到首位,不仅是因为它是一个函数标志,还因为它是transition-timing-functionanimation-timing-function 这两个函数的默认值。

The step function

最后要讲的是,我们看一下一些影响你属性改变速率的其它东西,但它不是缓动函数。这种不是缓动函数被称之为 step function(步进函数):

Animation Img

Step function是很特别的。它影响着不同间隔内运行的动画。例如,你看到上面图表中的第一个阶段,动画属性比率开始于0%处。在完成率50%标记处,动画一下子跳到50%。在动画完成时属性的比率到达100%。这些不同帧或步都不是平滑的。结果看起来有点像锯齿。

在CSS中,使用 steps 函数定义步进函数:

.pictureContainer img {
    position: relative;
    top: 0px;
    transition: top 1s steps(2, start);
}

步进函数有两个参数:

    1. 总步数
    1. 第二个参数值为start或end,用来指定动画在每一步的开始时触发,还是在每一步的结束时触发。

例如,如果我想让动画分成5步并在每步的结束时触发,步进函数的定义看起来如下:

.pictureContainer img {
    position: relative;
    top: 0px;
    transition: top 1s steps(5, end);
}

需要注意的一件事是,指定越多的步数,动画越平滑。毕竟,把每一步当做动画的每一帧。相同时间内,定义越多的帧,最终的动画越平滑,这同样适用于步进声明的动画。

Further Reading

鉴于一般流行和计算机生成的动画,你可阅读关于它们更多好东西的细节。下面列出我最喜欢的:


翻译水平有限,敬请各位同学批评指正。


Comments

comments powered by Disqus