4、缓动函数艺术:内置缓动函数与cubic-bezier()自定义曲线

动画做出来生硬还是流畅,关键就在缓动函数。

说白了,缓动函数就是控制动画速度变化的工具。没有它,所有动画都是匀速的,像机器人一样僵硬。我刚开始做前端时,觉得动画嘛,能动就行。后来被设计师怼了几次,才真正重视起这个细节。

4.1 五个内置缓动函数

CSS 给我们准备了五个现成的缓动函数。它们覆盖了大部分日常场景。

函数名 效果描述 适用场景
linear 全程匀速,没有加速减速 进度条、加载旋转
ease 慢→快→慢,默认值 通用过渡,最自然
ease-in 慢→快,起步慢 元素进入、弹窗出现
ease-out 快→慢,结尾慢 元素消失、按钮反馈
ease-in-out 慢→快→慢,两头慢 轮播切换、卡片翻转

核心记忆点:ease-in 适合「进来」,ease-out 适合「出去」。别搞反了,否则看起来像在跟用户较劲。

/* 基础用法 */
.box {
  transition: transform 0.3s ease-out;
}

.box:hover {
  transform: scale(1.1);
}

嗯,这里要注意:ease 是默认值。如果你不写 transition-timing-function,浏览器就用 ease。但我不建议依赖默认值——显式写出来,代码可读性更好,别人一看就知道你的意图。

4.2 cubic-bezier():真正的控制权

内置函数虽然方便,但不够灵活。比如你想让动画先快后慢再快,内置函数就做不到了。

这时候就需要 cubic-bezier()。它用四个参数定义一条贝塞尔曲线,控制动画速度的变化。

/* 语法:cubic-bezier(x1, y1, x2, y2) */
.custom-ease {
  transition: transform 0.5s cubic-bezier(0.25, 0.1, 0.25, 1);
}

四个参数对应两个控制点的坐标。x 值必须在 0 到 1 之间,y 值可以超出范围——超出就会产生「回弹」效果。

我的小技巧:别硬记参数。用 Chrome DevTools 的动画调试面板,拖拽曲线实时预览,找到感觉再复制参数。我每次做新项目都会打开它调一调。

4.3 打造真实物理感

为什么有些动画看起来「假」?因为现实世界没有匀速运动。物体启动时有惯性,停止时有阻力。

我做过一个卡片拖拽排序的功能。一开始用 ease-out,总觉得卡片「飘」过去的,不像被手拖动的。后来换成自定义贝塞尔曲线,才找到那种「被拽着走」的感觉。

/* 模拟弹簧效果 */
.spring {
  transition: transform 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55);
}

/* 模拟重力下落 */
.fall {
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

/* 模拟弹性碰撞 */
.bounce {
  transition: transform 0.5s cubic-bezier(0.5, 1.5, 0.5, -0.5);
}

我曾经踩过的坑:y 值超出 [0, 1] 范围会产生回弹效果,看起来很酷。但回弹幅度太大,或者动画时间太短,会让用户觉得「晃眼」。尤其是按钮这种高频交互,回弹要克制。我一般把回弹幅度控制在 0.3 以内。

4.4 实战:弹窗动画

来,我们做一个完整的弹窗动画。要求:弹窗从底部滑入,先快后慢,带一点弹性。

.modal {
  transform: translateY(100%);
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.modal.active {
  transform: translateY(0);
}

为什么选这个曲线?0.34, 1.56 让开头加速快一点,0.64, 1 让结尾减速自然。y 值 1.56 超出 1,产生轻微回弹——弹窗到位后会「抖」一下,很像真实物理碰撞。

你想想看,如果换成 ease-out,弹窗会匀速滑入然后突然停住,像撞墙一样。加了回弹后,用户会觉得「这东西有重量」。

4.5 常用曲线速查表

我整理了一份自己常用的曲线表,直接复制就能用。

效果 cubic-bezier 参数 说明
标准缓入 0.42, 0, 1, 1 等同于 ease-in
标准缓出 0, 0, 0.58, 1 等同于 ease-out
柔和缓出 0.25, 0.1, 0.25, 1 比 ease-out 更平滑
弹性进入 0.68, -0.55, 0.27, 1.55 过头再回弹
重力下落 0.22, 1, 0.36, 1 先慢后快再慢
快速弹起 0.5, 1.5, 0.5, -0.5 适合点赞动画

我的建议:先掌握 ease-outease-in-out,能解决 80% 的场景。剩下的 20% 再用自定义曲线精调。别一上来就搞复杂曲线,容易翻车。

4.6 避坑指南

最后说几个我踩过的坑。

  • 动画时间太短:回弹效果需要时间展现。如果 duration 小于 0.3s,回弹还没完成就结束了,看起来像抖动。我一般给回弹动画留 0.5s 以上。
  • 多个属性用不同曲线:同时改变 opacitytransform 时,可以用不同缓动函数。比如透明度用 ease,位移用 cubic-bezier。这样动画层次更丰富。
  • 别忘了无障碍:有些用户设置了「减少动画」偏好。用 prefers-reduced-motion 媒体查询,给这些用户提供无动画版本。我曾经忽略这个,被用户投诉过。
/* 尊重用户偏好 */
@media (prefers-reduced-motion: reduce) {
  .modal {
    transition: none;
  }
}

缓动函数是动画的灵魂。花时间调好它,你的页面会从「能动」变成「舒服」。下一章我们聊关键帧动画,到时候这些曲线知识会派上大用场。