使用CSS linear()函数实现更逼真的物理动画效果

这篇文章发布于 2025年09月15日,星期一,20:12,归类于 CSS相关。 阅读 94 次, 今日 90 次 没有评论

 

一、被低估的linear()函数

CSS动画曲线函数新增了一个名为linear()的函数,目前所有现代浏览器都已经支持:

linear()函数

一开始,我以为又是什么缝缝补补的新特性,细细一眼就,发现这东西还是挺强的。

之前的动画缓动函数我们都是使用cubic-bezier()函数,贝塞尔曲线实现的,但是这个函数有个问题,最多就4个属性值,只能实现先快后慢,先慢后快,或者一次性bounce缓动。

但是真实的物理动画往往是复杂的,例如一个皮球落地,他不可能只弹一下,往往要蹦很多下,cubic-bezier()函数就无法模拟。

在这种背景下,就设计了linear()函数,虽然是线性函数,但是参数是无限的,于是我们可以通过枚举的方式,可以模拟任何的运动曲线。

举个例子,小球落地的动画效果。

点击下面的篮球,可以查看对应的动画效果:

🏀

相关的HTML和CSS代码示意:

<div class="ballX">
  <span>🏀</span>
</div>
:root {
  --bounce-easing: linear(0, 0.004, 0.016, 0.035, 0.063, 0.098, 0.141 13.6%, 0.25, 0.391, 0.563, 0.765, 1, 0.891 40.9%, 0.848, 0.813, 0.785, 0.766, 0.754, 0.75, 0.754, 0.766, 0.785, 0.813, 0.848, 0.891 68.2%, 1 72.7%, 0.973, 0.953, 0.941, 0.938, 0.941, 0.953, 0.973, 1, 0.988, 0.984, 0.988, 1);
}
.ballX {
  height: 200px;
  border-bottom: solid;
}
.ballX span {
  animation: fallDown 1s var(--bounce-easing);
}
@keyframes fallDown {
  from { translate: 0 -150px; }
  to { translate: 0 0; }
}

如果希望弹动更加逼真,我们可以提高函数参数的精度(切分更细致),就像这样:

:root {
  --bounce-easing: --linear(0 0%, 0.0009 0.7117%, 0.0034 1.3049%, 0.0144 2.6097%, 0.0586 5.2195%, 0.1313 7.8292%, 0.2356 10.5575%, 0.5338 16.2515%, 1 23.1317%, 0.8675 25.86%, 0.7715 28.707%, 0.7383 30.1305%, 0.7129 31.6726%, 0.6991 33.0961%, 0.6952 33.9265%, 0.6944 34.6382%, 0.6957 35.3499%, 0.6994 36.0617%, 0.7133 37.4852%, 0.7361 38.9087%, 0.7705 40.4508%, 0.8638 43.4164%, 1 46.6192%, 0.9404 48.5172%, 0.8981 50.4152%, 0.8725 52.3132%, 0.8657 53.2622%, 0.8629 54.3298%, 0.8647 55.2788%, 0.8705 56.2278%, 0.8959 58.2444%, 0.9357 60.1423%, 1 62.3962%, 0.9487 65.1246%, 0.9362 66.4294%, 0.9326 67.1412%, 0.9312 67.8529%, 0.9321 68.5647%, 0.9352 69.2764%, 0.9482 70.6999%, 1 73.5469%, 0.9742 75.4448%, 0.9675 76.3938%, 0.9646 77.4614%, 0.9663 78.4104%, 0.973 79.4781%, 1 81.6133%, 0.986 83.0368%, 0.9824 83.7485%, 0.9811 84.4603%, 0.982 85.172%, 0.9852 85.8837%, 0.9997 87.4259%, 0.9918 88.7307%, 0.9898 89.7983%, 0.9923 90.7473%, 0.9998 91.8149%, 0.9954 92.8826%, 0.9945 93.5943%, 0.9959 94.306%, 1 95.1364%, 0.9981 95.6109%, 0.9972 96.3227%, 1 97.3903%, 0.9988 98.102%, 0.9998 98.8138%, 1 100%);
}

二、linear()函数如何使用?

大家无需关心linear()的语法,因为实际使用的时候,都是通过工具生成的。

这里介绍两个工具:

  • linear-easing-generator
  • Nordcraft css-linear

    这个工具在上面链接文章的中间部分,如下截图所示,选择对应的动画类型,可以看到对应的运动曲线、效果预览和对应的代码:

    liner()效果示意

这里,重点介绍下上面的工具(仓库地址:linear-easing-generator),因为其支持自定义实现。

缓动函数转linear()代码

网上有很多动画函数的,例如比较经典的Bounce弹动函数:

1 - Math.abs(Math.cos(t * 3.5 * Math.PI) * (1 - t))

使用的时候,我们直接将linear-easing-generator这个页面左侧的函数替换成下图所示的这样:

缓动函数示意

此时,此工具就会帮我买生成对应的linear()函数代码(如下图所示),其中的CSS变量名称就是self.xxxx后面的属性值决定的,我们还能调整动画的精度。

生成代码示意

更多的缓动函数

不得不提一下我的这个Tween.js项目( https://github.com/zhangxinxu/Tween ),目前Star已经破千了。

其中展示了十几个经典的各种缓动函数算法,访问见这里

不过这些函数都是4个参数(如下图所示),我们需要将部分参数常量化才能使用:

代码参数示意

以Bounce.easeOut方法举例,这是其原本的函数:

Bounce.easeOut = function(t, b, c, d) {
    if ((t /= d) < (1 / 2.75)) {
        return c * (7.5625 * t * t) + b;
    } else if (t < (2 / 2.75)) {
        return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
    } else if (t < (2.5 / 2.75)) {
        return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
    } else {
        return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
    }
}

我们只需要将b, c, d参数设置为常量值就可以了,如下所示:

self.bounceEaseOut = function(t) {
  const d = 1.333;
  const b = 0;
  const c = 1;
  if ((t /= d) < (1 / 2.75)) {
      return c * (7.5625 * t * t) + b;
  } else if (t < (2 / 2.75)) {
      return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
  } else if (t < (2.5 / 2.75)) {
      return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
  } else {
      return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
  }
}

此时,右下角就可以看到如下所示的linear()函数代码了,学到了木有?

:root {
  --bounce-ease-out-easing: linear(0, 0.004, 0.016, 0.035, 0.062, 0.098, 0.141, 0.191, 0.25 24.2%, 0.39, 0.562, 0.765, 1 48.5%, 0.943, 0.893, 0.851, 0.816, 0.788, 0.768, 0.755, 0.75, 0.753, 0.763, 0.782, 0.809, 0.844, 0.888, 0.94, 1, 0.972);
}

生成曲线和动画效果示意

三、了解下linear()函数的原理

linear() 函数的核心在于让动画进度在指定的多个关键点之间以恒定速率变化,但不同区段可以设置不同的进度变化速度,从而形成一种“分段线性”的缓动效果。

  • 接受参数:它接受两个或更多的数值参数,这些参数代表动画的进度(通常介于 0 到 1 之间,0% 表示动画开始,100% 表示完成)。
  • 分段线性:浏览器会根据你提供的这些点,计算出多个线性的速度段。在每个区段内,动画的速度是恒定的,但不同区段之间速度可能会发生突变(直接转折)。
  • 可选百分比:你还可以为每个进度点指定一个时间百分比,用以控制该进度点出现在动画持续时间的哪个时刻。如果不指定,浏览器会自动在时间上均匀分布这些进度点。

语法和参数

linear() 函数可以用于 animation-timing-functiontransition-timing-function 属性。

/* 语法 */
animation-timing-function: linear(<点列表>);
transition-timing-function: linear(<点列表>);

参数示例与解释

  • linear(0, 1):这表示从开始 (0) 到结束 (1) 的速度是恒定的。它的效果与关键字 linear 完全相同。
  • linear(0, 0.9, 1):这表示动画的前 50% 的时间播放了整体进度的前 90%,而后 50% 的时间仅播放剩下的 10% 的动画。这意味着前半段动画“很快”,后半段动画“很慢”。
  • linear(0, 0.5 20%, 0.8 60%, 1):这是一个更复杂的例子,它通过百分比精确指定了进度点出现的时间:
    • 前 20% 的时间:动画从 0% 进展到 50%。
    • 中间 40% 的时间(从 20% 到 60%):动画从 50% 进展到 80%。
    • 最后 40% 的时间(从 60% 到 100%):动画从 80% 进展到 100%。

与其他缓动函数对比

缓动函数 特点 适用场景
linear() 分段恒定速度,速度变化直接转折 需要精确控制不同阶段进度变化速率的动画
linear (关键字) 从开始到结束完全恒定的速度 进度条、机械感强的动画
ease (默认) 慢速开始,加速,然后慢速结束 大多数UI交互,如按钮悬停、菜单展开
ease-in 慢速开始,逐渐加速 元素从页面中离开
ease-out 快速开始,逐渐减速 元素进入页面
ease-in-out 慢速开始和结束,中间较快 具有明确开始和结束状态的动画
cubic-bezier(n,n,n,n) 通过贝塞尔曲线自定义速度曲线,可创建非常丰富和自然的加速度变化 当预定义函数无法满足需求,需要特定加速度模型时

四、最后的小结

linear() 函数为你提供了另一种控制动画节奏的工具。它不是通过平滑的加速度曲线,而是通过定义多个关键进度点及其(可选的)出现时间,来创建一种分段恒速、速度变化直接转折的动画效果。当你需要实现一些非传统、有特定节奏或阶梯式进度变化的动画时,linear() 会非常有用。

最后,渔获展示时间,周六钓的,钓费120元,两条鱼加起来10斤出头一点,切线两个大的:

渔获

😉😊😇
🥰😍😘

(本篇完)

分享到:


发表评论(目前没有评论)