1. 线性运动(linear)
  2. 缓入(ease-in)
  3. 缓出(ease-out)
  4. 缓入缓出(ease-in-out)
  5. 其他运动效果
  6. 附录
  7. 参考

缓动函数(easing function)

网页设计经常会用到各种动画效果.
现实世界的大多数运动都是变速的.与变速运动相比,匀速运动就显得很生硬,给人一种不自然的感觉.

css可以用timing-function参数来实现变速运动.
但不是所有的动画都能用css来解决, 例如下拉刷新, 要用js来根据touchmove的距离来绘制动画效果.
这时就可以用缓动公式来实现各种动画效果.

线性运动(linear)

线性运动的计算公式为: f(x) = x
1.PNG

将线性运动映射到横向移动上,每次移动的距离都是相等的
11.PNG

具体的代码如下:

  • currentTime 当前时间
  • duration 动画时长
  • startValue 起始位置
  • changeValue 总移动距离
1
2
3
function linear(currentTime, startValue, changeValue, duration) {
return changeValue * currentTime / duration + startValue;
}

对应到坐标轴上, currentTime是x轴上某点(记为点a), duration是x轴长度,startValue和changeValue分别是y轴起点和长度.返回值是点a对应的y轴坐标.

缓入(ease-in)

开始时速度很慢, 然后逐渐加快.结尾会突然停止,感觉很生硬.

缓入的计算公式为: f(x) =x * x
in.PNG

将ease-in映射到横向移动上,可以观察到开始很慢, 然后逐渐变快, 在结尾时速度最快.
inv.PNG

具体的代码如下:

1
2
3
4
function easeInQuad(currentTime, startValue, changeValue, duration) {
currentTime /= duration;
return changeValue * currentTime * currentTime + startValue;
}

上面代码的执行步骤为:

  • 将"当前时间"映射[0, 1]间(currentTime /= duration)
  • 根据缓入公式计算出"当前时间"应该移动的百分比(currentTime * currentTime)
  • 根据"总移动长度"和"移动百分比"算出应移动的具体值(changeValue * ...)
  • 加上初始位置(+ startValue)

函数名easeInQuad中Quad指的是二次方, 也就是乘两次.
其它的easeIn函数还有easeInCubic(x^3), easeInQuart(x^4), easeInQuint(x^5).
乘的次数越多, 速度变化的幅度越大.

缓出(ease-out)

常用的变速运动, 开始时速度很快,给人一种流畅感.然后逐渐减速, 不会让人觉得戛然而止.

缓出的计算公式为: f(x) = -xx+2x
其实就是ease-in函数的镜像翻转
easeout.PNG

将ease-out映射到横向移动上,可以观察到开始时速度最快, 然后逐渐变慢,在结尾时速度最慢.
easeout.PNG

具体的代码如下:

1
2
3
4
function easeOutQuad(currentTime, startValue, changeValue, duration) {
currentTime /= duration;
return -changeValue * currentTime * (currentTime - 2) + startValue;
}

缓入缓出(ease-in-out)

开始和结尾慢时, 中间快.比缓出更生动.
动画时间不宜过长, 最好在300~500ms间.
ease-in-out和ease非常相似,不同点在于ease的开始速度比结束速度更快一些.

ease-in-out是ease-in和ease-out的结合,前半段用ease-in的计算公式,后半段用ease-out的计算公式.
inout.PNG

将ease-in-out映射到横向移动上,可以观察到开始速度慢, 然后逐渐变快,到中间时达到最大值, 然后又逐渐减慢.
inoutw.PNG

具体的代码如下:

1
2
3
4
5
6
easeInOutQuad(currentTime, startValue, changeValue, duration) {
currentTime /= duration / 2;
if (currentTime < 1) return changeValue / 2 * currentTime * currentTime + startValue;
currentTime--;
return -changeValue / 2 * (currentTime * (currentTime - 2) - 1) + startValue;
}

上面代码的执行步骤为:

  • 将当前时间映射到[0, 2]间(currentTime /= duration / 2)
  • 如果"当前时间"小于1, 则用ease-in公式计算.除2是因为y轴(总长度)实际上只有一半,后面一半用ease-out计算.
  • 如果"当前时间"大于等于1,则用ease-out公式计算

inout1.png

其他运动效果

还有很多复杂的过渡函数,访问如下的网站来查询更多的过渡函数及效果

附录

过渡函数曲线

See the Pen easing function(x,y) by aaronbird (@aaronbird) on CodePen.

横向移动速度

See the Pen easing function by aaronbird (@aaronbird) on CodePen.

参考

缓动公式小析
https://developers.google.com/web/fundamentals/design-and-ux/animations/the-basics-of-easing?hl=zh-cn
如何使用Tween.js各类原生动画运动缓动算法 « 张鑫旭-鑫空间-鑫生活