轻松自如:缓动函数入门

Avatar of Pavithra Kodmad
Pavithra Kodmad

DigitalOcean 为您的每个旅程阶段提供云产品。立即开始使用 200 美元的免费积分!

在过去的几个月里,我一直积极地自学如何绘制和动画 SVG 形状。我一直在使用 CSS 过渡以及 D3.jsreact-motionGSAP 等工具来创建我的动画。

通常情况下,关于动画及其工具的文档都建议使用 **缓动函数**。这些年来我一直以某种方式使用它们,但说实话,我永远不知道应该为哪种动画选择哪个函数。此外,我不知道每个函数的魔力,它们之间的显著差异以及如何有效地使用它们。但我对此很满意,因为我知道缓动函数在某种程度上“平滑”了事物,并使我的作品看起来更加逼真。

在这里,我将向您介绍我学到的有关缓动函数的知识,以入门指南的形式,我希望它能为您深入了解动画提供很好的理解。

我如何接触到缓动函数

我尝试重新创建一个名为旋转蛇的图案,这是一种视觉错觉,它欺骗大脑以为圆圈在旋转和“跳舞”,而实际上它们并没有。

在尝试构建它时,我很快发现自己知识上的不足。这很难!但在过程中,我发现缓动函数在其中起着重要作用。

我转向 JavaScript,使用一个库在 SVG 中绘制了许多同心圆。

for (i = 1; i <= 10; i++) {
  drawCircle({radius: i * 10});
}

这是结果

但这显然不像图片那样。

经过思考,我意识到自己想要一个特定的属性。我希望同心圆的半径变化在开始时很小,然后随着半径的增加而变大。

这意味着使用 i++ 线性增加半径将不起作用。我们需要一个更好的公式来推导出半径。所以,我的下一次尝试看起来像这样

let i = 1;
let radiusList = [];
let radius = 0;
while (i <= 10) {
  drawCircle({radius: i * 10});
  if(i < 4) { i = i + 0.5 } else { i = i + 1 } 
}

…这让我得到了这个

嗯,这仍然不是我想要的。事实上,这与图案的偏差更大。此外,这段代码几乎不可定制,难以维护。

所以我转向数学,尝试最后一次。

我们需要一个函数,它可以有机地和指数地改变半径。我突然灵机一动,也许你已经看到了。缓动函数可以做到这一点!

每个圆的半径应该在一开始缓慢增加,然后随着圆向外移动而快速增加。使用缓动,我们可以使事物沿着一条曲线移动,该曲线可以在某些点减速和加速。

快速谷歌搜索将我带到了 这个 gist,它是一个记录良好的缓动函数列表,真的救了我。每个函数接受一个输入值,运行公式,并提供一个输出值。输入值必须介于 0 和 1 之间。(我们将在后面深入探讨这个原因。)

二次缓动函数看起来很有希望,因为它所做的只是对它接收的值进行平方。

function (t) { return t*t }

这是我最终使用的代码

const easing = (t) => {
  return t*t
}
for(i = 0; i<=1; i=i+0.05) {
  const r = easing(i) * 40;
  drawCircle(r);
}

我们找到了赢家!

这个图案与我的前两次尝试之间的区别是天壤之别。欢呼缓动函数!

这段小小的经历让我对缓动函数还能做什么产生了浓厚的兴趣。我在互联网上搜寻了有关它的酷炫信息。我找到了旧文章,大部分与 Flash 和 ActionScript 相关,这些文章有演示展示了不同的线形图。

这些都过时了,所以这是我关于缓动函数的小入门指南。

什么是缓动函数?

它们是一种函数,接受介于 0 和 1 之间的数值输入。该数字通过指定的函数运行,并返回另一个介于 0 和 1 之间的数字。**介于 0-1 之间的数值乘以另一个介于 0-1 之间的数值,始终得到一个介于 0-1 之间的数值。**这种特殊的性质帮助我们在特定边界内进行任何我们想要的计算。

缓动函数的目的是从 **线性值输入** 中获得 **非线性值**。

这是关于缓动函数我们需要知道的关键。从现在开始的所有解释和演示都将围绕这个概念展开。

缓动函数是 数学中的插值概念 的体现。插值是找到位于曲线上的点的集合的过程。缓动函数本质上是通过插值(计算)沿途的不同点集来从点 0 到点 1 绘制一条曲线。

Robert Penner 是第一个在他的 中定义缓动函数并创建不同缓动函数公式的人。

五种类型的缓动函数

有五种类型的缓动函数。它们可以混合、反转,甚至可以混合在一起形成更多复杂的函数。让我们深入研究每一种。

线性缓动函数

这是最基本的缓动形式。如果我们在 0 和 1 之间插值的点之间的间隔是恒定的,那么我们将形成一个线性缓动函数。

回到之前同心圆的例子,以恒定的量(在该例子中为 10px)增加初始圆的半径,会形成一个线性函数。

毫不奇怪,线性是默认的缓动函数。它们非常简单,因为动画没有曲线,物体以直线、一致的方向移动。也就是说,线性函数也有其缺点。例如,线性动画往往感觉不自然甚至很机械,因为现实生活中的物体很少以如此完美的直线运动。

二次缓动函数

二次缓动函数是通过将介于 0 和 1 之间的数值乘以自身(例如 0.5*0.5)来创建的。正如我们之前所学到的,我们看到这将得到一个也介于 0 和 1 之间的数值(例如 0.5*0.5 = 0.25)。

为了演示,让我们使用二次函数在 0 和 1 之间生成 10 个值。

const quad_easing = (t) => t*t;
let easing_vals = [];
for(let i = 0; i < 1; i +=0.1) {
  easing_vals.push(quad_easing(i));
}

这是一个表格,包含我们得到的所有值

输入值(x 轴) 二次缓动值(y 轴)
0 0
0.1 0.01
0.2 0.04
0.3 0.09
0.4 0.16
0.5 0.25
0.6 0.36
0.7 0.49
0.8 0.64
0.9 0.81
1 1

如果我们将这个值绘制在以 x 轴为原始值、y 轴为缓动值的图表上,我们将得到类似这样的东西

注意到什么了吗?这条曲线与我们通常在 CSS 中看到的 ease-in 函数几乎一样!

三次、四次和五次缓动函数

最后三种类型的缓动函数行为相同,但使用不同的值。

三次缓动函数是通过将介于 0 和 1 之间的数值乘以自身三次来创建的。换句话说,它是一些值(例如 t),立方(例如 t3)。

四次函数做同样的事情,但为 4 次方。所以,如果 t 是我们的值,我们正在查看 t4

正如你已经猜到的,五次函数运行到 5 次方。

以下演示将为您提供一种方法来玩转五种类型的函数,以便直观地了解它们之间的区别。

查看 CodePen 上 Pavithra Kodmad (@pkodmad) 的 绘制缓动函数 Pen。

缓入和缓出…或者两者!

“缓入缓出是一种美味的半半结合,就像香草巧克力漩涡冰淇淋甜筒。”
— Robert Penner

缓入和缓出可能是最常见的缓动动画。它们通常通过在动画的开始或结束(或两者!)减速来平滑典型的线性线条。

缓入和缓出动画可以使用我们已经看过的任何非线性函数来创建,尽管三次函数最常使用。事实上,CSS animation 属性通过 animation-timing-function 子属性,直接提供了 ease-inease-out 值。

  • ease-in:此函数开始缓慢,但结束更快。
  • ease-out: 此函数开始时速度快,结束时速度慢。
  • ease-in-out: 此函数是其他函数的组合,开始时速度快,中间速度慢,然后结束时速度快。

查看 CodePen 上 Pavithra Kodmad 的 缓动演示 (@pkodmad)。

可以在这里 cubic-bezier.com 上试用它们。

这些曲线也可以在 JavaScript 中创建。我个人喜欢并使用 bezier-easing 库来实现它。 Easing.js 也是一个不错的选择,还有 D3 库(来自 Mike Bostock 的 不错的示例)。如果你更喜欢 jQuery,可以看看 这个插件 甚至 这个插件

看到了吧,真的很“容易”!

我希望这个简短的入门介绍能够帮助说明缓动函数和插值的概念。这些函数可以使动画更加自然和逼真,方法很多。可以查看 Easing.css,它提供一个用户界面,可以创建自定义曲线,并附带大量预设选项。

我希望下次你使用缓动函数时,它不再是一个黑盒子。你现在拥有了一个基本了解,可以将缓动函数付诸实践,并在处理动画时打开更多可能性。

更多关于缓动的内容

我们在这里只触及了缓动函数的表面,但 CSS-Tricks 上还有其他很好的资源值得一阅,可以让你更上一层楼。