CSS cubic-bezier 曲线生成器,免费

拖动控制点创建自定义 CSS 缓动函数。预览动画并复制代码。

CSS 代码

Cubic Bézier 时间函数到底是什么

在 CSS 里,时间函数会把已经过去的时间(输入,从动画开始的 0 到结束的 1)映射到一个进度值(输出,约定上也是 0 到 1,但允许溢出)。被动画的属性(opacity、translate、color,任何 CSS 能过渡的东西)会以时间函数所描述的速率,在它的起点值与终点值之间做插值。线性的时间意味着属性以恒定速度移动;各种 ease 函数则做加速、减速,或者两者都做。cubic-bezier(x1, y1, x2, y2) 是它的一般形式:一条从 (0,0) 到 (1,1) 的 Bézier 曲线,带有两个自由的控制点 P1 和 P2,由你用四个数字来指定。浏览器在动画的每一帧都会沿着这条曲线采点,以决定属性此刻的进度。这四个数字定义了两个控制点:P1 = (x1, y1) 决定曲线起点的形状(通常两条轴都在 0–1 之间),P2 = (x2, y2) 决定终点的形状。x 值必须留在 [0, 1] 内,这样曲线对时间才是单值函数;y 值则可以越过 [0, 1],从而产生过冲与回弹效果(y 取 1.2 意味着属性会在最终落定之前短暂地越过它的目标值)。

Bézier 曲线,它的数学血脉

这些曲线得名于 Pierre Bézier,一位在 Renault(雷诺)工作的法国工程师。他在 1960 年代用它们来设计 Renault 16 那些光滑的车身钣金,这些工作于 1968 年作为雷诺 UNISURF CAD 系统的一部分公开发表。同一套数学,其实更早在 1959 年就已经被 Citroën(雪铁龙)的 Paul de Casteljau 独立发展出来;只是雪铁龙把 de Casteljau 的成果当作商业秘密保留下来,因此 Bézier 公开的版本反而成了规范的参考。两人最后汇聚到了同一族由控制点定义的多项式曲线上,以这位未发表的先驱命名的 de Casteljau 算法正是用来在给定参数处求 Bézier 曲线值的。三次 Bézier 曲线之所以成为矢量图形的通用基本单元,是因为它们求值便宜(几次乘加)、平移缩放轻而易举(数学在仿射变换下不变)、并且具有局部可控性(移动一个控制点只会改变附近的曲线段)。Adobe PostScript(1984 年)和 PDF、SVG 规范(W3C 推荐标准 2001 年 9 月)以及每一种现代字体格式,都以三次 Bézier 曲线作为字母、图标和插画的构造单元。CSS 之后则把同样这种曲线类型借给了动画时间,把视觉设计世界里那个标准的数学基本单元,借用到「描述运动」这个新的用例上。

CSS Animation 规范与时间函数

CSS 动画和过渡使用的是同一族时间函数。CSS Animations Level 1 规范最早在 2009 年 3 月作为公开 Working Draft 发表(从更早带 WebKit 前缀的实现里抽取出来),并仍由 W3C CSS Working Group 持续维护。CSS Easing Functions Level 1 模块把时间函数语法正式化,目前是 Candidate Recommendation。五个具名关键字其实只是某些特定 cubic-bezier 的别名:ease = cubic-bezier(0.25, 0.1, 0.25, 1)(CSS 过渡的默认值,开头快、结尾慢,对绝大多数 UI 运动来说都自然。ease-in = cubic-bezier(0.42, 0, 1, 1))开头慢,最后加速到一个快的结尾。ease-out = cubic-bezier(0, 0, 0.58, 1)(开头快,向慢的结尾减速;这通常是用于元素从外面进入视口时使用最广的一种 easing。ease-in-out = cubic-bezier(0.42, 0, 0.58, 1))对称的 S 形曲线,两头都慢。linear = cubic-bezier(0, 0, 1, 1),没有 easing,恒速;很少是 UI 的最佳选择,但对像 spinner 这样的连续循环动画来说是合适的。CSS 还提供了两种非 Bézier 的时间选项:steps(n, jumpterm) 用于阶梯式(逐帧)动画,以及 linear()(在 CSS Easing Level 2 中加入),用于以分段线性的方式去近似任意曲线。

设计系统里的 easing 曲线

主流设计系统都会发布有自己主张的 easing 曲线,覆盖 CSS 的默认值。Google Material Design 把「standard easing」定为 cubic-bezier(0.4, 0, 0.2, 1),快速加速、缓慢减速,被用于 Android 和 Web Material 库里的大多数 UI 过渡;进入屏幕的元素用「decelerated easing」cubic-bezier(0, 0, 0.2, 1);离开屏幕的元素用「accelerated easing」cubic-bezier(0.4, 0, 1, 1)Apple 的 Human Interface Guidelines 更强调用 spring(弹簧)物理动画而不是固定的 Bézier 曲线,但 iOS 的 UIKit 默认带的 cubic-bezier 大致是 (0.25, 0.1, 0.25, 1)(和 CSS 的 ease 一样)。IBM 的 Carbon Design System 在它的「productive motion」类别里使用 cubic-bezier(0.5, 0, 0.1, 1)Microsoft FluentAtlassianSalesforce Lightning 都各自定了自己的曲线。Robert Penner 的 easing 方程(2001 年随他写的关于 Flash 动画的书一并发表)定义了几乎每一个动画库都在用的那套具名曲线词汇,easeInQuad、easeOutCubic、easeInOutSine、easeInQuart、easeOutBack、easeInOutBounce、easeInElastic。它们里大多数都能用 cubic-bezier 表示;但 elastic 和 bounce 这一类的不行(因为它们会振荡,必须用多段的分段函数才行)。

为不同情况选合适的曲线

性能方面的考虑

自定义的 cubic-bezier 时间函数在运行时几乎是免费的,曲线是个常量,浏览器会一次性把查找表预先算好,每帧只有几条浮点运算。性能问题真正在哪儿,取决于你动画的是哪个属性,而不是时间曲线。给 transform(translate、scale、rotate)和 opacity 做动画用的是 GPU 合成,即便在中端硬件上也能稳定 60 或 120fps。但要给 topleftwidthheightmarginpadding 或任何会触发 layout 的属性做动画,那除了最简单的页面之外几乎都会卡(因为每一帧都会触发整页 reflow。「合成器友好」的属性集合(transform + opacity,加上 filter 和少数其他几个)是通常的安全集合;其他一切都需要在真实页面负载下实测一下。CSS 的 will-change 属性是给浏览器一个提示)某个属性即将被动画,让浏览器提前把这个元素提升到自己单独的合成层;不过要省着用,因为每个 will-change 都会预占一份 GPU 内存。

无障碍:prefers-reduced-motion

有相当一部分用户(患有前庭功能障碍、注意力缺陷类问题,或者只是单纯不喜欢)会觉得运动设计令人分心,甚至直接不舒服。CSS Media Queries Level 5 规范定义了 prefers-reduced-motion 这个 media feature,并把它作为系统设置暴露在 macOS(系统设置 → 辅助功能 → 显示 → 减弱动态效果)、Windows 10+(设置 → 轻松使用 → 显示)、iOS、Android 以及主流的 Linux 桌面里。从 2019 年前后开始的惯例是:把所有非必要的动画包在 @media (prefers-reduced-motion: no-preference) { ... } 里,或者反过来用 @media (prefers-reduced-motion: reduce) { transition: none !important; animation: none !important; }。在这件事情上你具体选哪条 cubic-bezier 曲线并不重要,规范要求的是:当用户已经表达了偏好时,开发者就应当关掉、或者明显缩短这段动画。现代设计系统的文档(Material、Atlassian、GOV.UK)里也都写有「降低动效」相关的指引。

弹簧物理,更新一些的替代方案

Cubic-bezier 时间函数把运动描述成沿着一条手动调好的曲线、做固定时长的插值。弹簧物理则把运动描述成一个有阻尼的谐振子自然落定的过程:你指定质量、刚度和阻尼,然后动画一直跑到弹簧静止下来为止。对于可以被打断的 UI 手势,弹簧给人的感觉更自然,因为它带着惯性、能在中断之后继续延续,比如你在 flick 手势进行到一半时松开手,弹簧会沿着一条新的曲线继续走向目标,而不是直接「啪」一下跳过去。Apple 的 iOS 在大多数原生交互上都用了弹簧物理(滚动到边缘时的回弹、滑动时的橡皮筋效果)。React Spring(Paul Henschel)、Framer Motion,以及 CSS 的 linear() easing 函数(喂给它一条采样过的弹簧曲线时),也都把弹簧的语义带进了 web。对于固定时长的 UI 过渡,cubic-bezier 仍然是合适的工具;对于由手势驱动、可以被打断的运动,弹簧才是合适的工具。这个编辑器产出的是 cubic-bezier,对于 2026 年里 90% 的 UI 动画工作来说,正是合适的形式。

什么时候你会去用这个工具

常见问题

这些数值代表什么?

它们定义了一条从 (0,0) 到 (1,1) 的三次 Bézier 曲线的两个控制点。P1 = (x1, y1) 决定曲线起点的形状;P2 = (x2, y2) 决定终点的形状。x 轴是时间(必须在 [0, 1] 里);y 轴是动画进度(如果想要过冲效果可以越过 [0, 1])。y > 1 表示属性会在落定之前短暂地越过它的目标值;y < 0 表示属性会在朝目标接近之前先短暂地往反方向走一下。

CSS 默认的 easing 是哪一种?

对于 CSS 过渡(transition: opacity 300ms;),默认是 ease,等价于 cubic-bezier(0.25, 0.1, 0.25, 1),开头快,结尾慢。对于 CSS 动画(animation: foo 1s;),默认也是 ease。可以用 transition-timing-functionanimation-timing-function 来覆盖。在大多数 UI 运动里,用 ease-out 这一变体或者 Material 风格那种减速曲线,往往会比默认值的手感更好。

我怎么做出弹跳或者过冲的效果?

把 y2 推到 1 以上(典型值 1.2–1.6),让曲线在落定前短暂地超过目标值。一种很常见、又比较克制的弹跳是 cubic-bezier(0.34, 1.56, 0.64, 1)。要做明显的弹跳,那你需要的就不是单条 cubic-bezier,而是弹簧物理或多 keyframe 的动画,bezier 曲线只能有一个峰值,所以真正意义上的弹跳(多次震荡)需要在中间的几步加 keyframes。

自定义曲线会不会比那些具名关键字慢?

不会,那些具名关键字本来就只是某些特定 cubic-bezier 的别名,走的是同一条代码路径。性能取决于你动画的是什么属性(transform/opacity = GPU 合成,速度快;像 top/left/width 这种会影响 layout 的属性 = 因为 reflow 而慢),而不是时间曲线。cubic-bezier 的求值开销可以忽略不计。

这个工具能离线工作吗?

可以,曲线 canvas、预览球的动画、CSS 代码生成,全部都是通过 JavaScript 在你的浏览器里跑。使用过程里没有任何网络请求。页面加载完成之后让它离线(飞行模式),这个编辑器照样能用。没有遥测;你最终选定的那一组曲线值永远不会离开你的设备。

相关工具