HandyTools Hub

贝塞尔曲线生成器

以可视化方式设计 CSS 时间函数并复制 cubic-bezier 值

拖拽两个控制点塑造曲线。水平方向限制在框内;垂直方向可超出框外,实现回弹效果。

当前曲线

线性(参考)

 

cubic-bezier 生成器让你通过拖拽两个控制点,可视化地设计 CSS 时间函数,再复制出精确的 cubic-bezier(x1, y1, x2, y2) 值。编辑器把水平坐标钳制在单位框内,允许垂直坐标越出框外以实现过冲,并用真实 CSS transition 预览曲线,让你在粘进样式表之前就判断出手感。

读懂曲线

时间函数是一条三次贝塞尔曲线,端点固定为 P0 = (0,0)、P3 = (1,1),两个手柄决定 P1 = (x1, y1) 和 P2 = (x2, y2)。给定时间进度 x,浏览器先找出满足 x(t) = x 的曲线参数 t,再返回 y(t):

x(t) = 3(1−t)²t·x1 + 3(1−t)t²·x2 + t³
y(t) = 3(1−t)²t·y1 + 3(1−t)t²·y2 + t³

由于 x1 和 x2 被限制在 [0,1],x(t) 单调上升,所以每个 x 都恰好有一个 t 与之对应。画布上的虚线对角线是线性函数 y = x,是每条曲线用来对照的基准。

操作步骤

  1. 从预设开始——点击 ease、ease-in-out、easeOutBack 或其他内置预设,载入已知的控制点。
  2. 拖拽手柄——拉动任意一个圆形控制点。水平拖动被钳制在单位框内;垂直拖动不受限制。
  3. 观察实时数值——cubic-bezier(...) 输出随每一次指针移动更新。
  4. 播放预览——用你生成的确切值驱动示例圆点,并与旁边的线性圆点对比。
  5. 复制——点击复制,把数值粘进 transition-timing-function 或 animation-timing-function。

实操示例:三种缓动在 50% 时刻

预设数值半程时的输出进度特征
easecubic-bezier(0.25, 0.1, 0.25, 1)y ≈ 0.802略快于线性,收尾柔和
easeOutBackcubic-bezier(0.175, 0.885, 0.32, 1.275)y ≈ 1.068半程已越过终点;峰值接近 1.087
easeInExpocubic-bezier(0.95, 0.05, 0.795, 0.035)y ≈ 0.037几乎不动,末尾猛冲

easeOutBack 的数字最值得记住:在 400 毫秒的过渡里,它会在约 63% 处超出最终位置约 9%,然后回落。缩短时长,这个回弹会显得干脆;拉长时长,过冲则显得拖沓。

过冲、预备与 x/y 规则

x 与 y 的不对称不是这个工具的怪癖,而是 CSS 规范本身。浏览器需要 x(t) 是一个函数,所以 x1、x2 必须落在 [0,1] 内,生成器替你钳制好。y1、y2 可以是任意实数:

  • y > 1——元素越过目标位置再返回。用于 toast、弹窗和按钮的弹跳。
  • y < 0——元素先向后退再向前走。用于预备动作,比如滑动前的蓄力。
  • 两者兼有——easeInOutBack 把低于 0 的下沉与高于 1 的过冲结合在一起。

精度与局限

  • 数值在打印前四舍五入到四位小数,与这些曲线通常被分享的精度一致。
  • 屏幕上的曲线通过数值求解 t 得到(牛顿-拉夫森法,迭代八次)。在极端的控制点取值下,可视曲线与浏览器的曲线可能相差一条亚像素级的轨迹,但打印出来的 CSS 值是精确的。
  • 工具只输出时间函数。它不生成 transition 或 @keyframes 块,不选择时长,也不决定对哪个属性做动画。
  • 曲线救不了不可动画的属性,也无法让 display 淡入淡出。这个工具设计的是运动,而不是让属性变得可动画。

从曲线到样式表

生成的字符串就是时间函数,所以可以直接放进任何过渡或动画:

.button { transition: transform 180ms cubic-bezier(0.175, 0.885, 0.32, 1.275); }
@keyframes pop { from { transform: scale(0.9); } to { transform: scale(1); } }
.toast { animation: pop 320ms cubic-bezier(0.68, -0.55, 0.265, 1.55) both; }

两个习惯会让这件事更省心。第一,让曲线匹配距离和时长:强烈的过冲放在长过渡里读起来像晃动,同一条曲线放在 150 毫秒里读起来则像干脆的一弹。第二,把少量常用曲线存进 CSS 变量,比如 --ease-snappy 和 --ease-bounce,让不同组件保持一致的运动质感,而不是各自发明一套。

常见错误

  • 什么都过冲。 按钮、卡片、弹窗都在弹跳的界面会显得嘈杂。每个视图里只为一两处焦点交互保留过冲。
  • 只复制曲线却不管时长。 手感来自这对组合;150 毫秒和 800 毫秒的 easeOutBack 是截然不同的效果。
  • 以为负的 y 是非法值。 不是——那是预备动作,浏览器会渲染它,工具也是有意允许的。
  • 用位移预览去判断所有属性。 transform 上的运动几乎说明不了 opacity 或颜色会如何插值,因为曲线是分别作用于每个属性的。

相关工具

常见问题

cubic-bezier(x1, y1, x2, y2) 里的四个数值是什么意思?

它们是一条锚定在 (0,0) 和 (1,1) 的三次贝塞尔曲线的两个控制点坐标:(x1, y1) 是第一个控制点,(x2, y2) 是第二个。x 轴表示时间进度,y 轴表示动画的输出进度,因此曲线的形状决定了运动如何加速与减速。

为什么 y 能高于 1 或低于 0,而 x 不行?

控制点的 x 必须保持在 [0,1] 内,因为时间不能倒流——曲线必须始终是进度的函数。控制点的 y 则自由:大于 1 会让动画冲过目标再回落(easeOutBack),小于 0 会让它先向后退(easeInBack)。回弹和预备动作正是这样构造出来的。

怎么做出过冲或回弹的效果?

把第二个控制点拖到方框顶边之上,让 y2 大于 1。`cubic-bezier(0.175, 0.885, 0.32, 1.275)` 会在超过终值约 8.7% 处达到峰值,然后回落。想做预备动作,就把第一个控制点拖到方框底边之下,令 y1 为负。

预览是真实的 CSS 动画还是模拟的?

是真实的。演示圆点使用真正的 `transition`,应用的就是你生成的 cubic-bezier 值,旁边还有一个线性参考圆点作对比。你看到的就是浏览器实际渲染的样子,包括任何过冲。

为什么 cubic-bezier 时间函数在某些属性上好像没效果?

时间函数只对可动画的属性做插值。像 `display` 这样的离散属性,无论给什么曲线都只在中点切换;不可动画的属性则瞬间跳变。如果什么都没有动,问题出在属性本身,而不是缓动。

怎样精确复刻设计系统里的缓动?

设计系统通常会公布四个控制点数值。你可以在编辑器里按这些值拖出对应位置,或从最接近的内置预设出发,每次只微调一个手柄。真正重要的是输出值,所以请直接复制 `cubic-bezier(...)` 字符串,而不是凭肉眼去凑。

由 HandyTools Hub 团队审校 · 最后更新