CSS cubic-bezier() 的數學:控制點、反函數與牛頓法
GDESIGN
設計發布: 10 分鐘閱讀

CSS cubic-bezier() 的數學:控制點、反函數與牛頓法

在 CSS 的 transition-timing-function 寫下 cubic-bezier(0.25, 0.1, 0.25, 1.0) 時,這四個數字究竟控制什麼?SVG 用貝茲曲線描述形狀,CSS 則用它把輸入進度轉換成輸出進度。兩端固定在 (0,0) 與 (1,1),兩個 x 控制座標必須介於 0 與 1 之間。本文從這項限制的數學理由出發,說明反函數、牛頓法與二分法。CSS Easing Functions 規範定義應有的輸出,並未指定瀏覽器內部必須採用哪一種數值求解方法。

日文原文發布: 2026-05-01

CSS 如何把貝茲曲線當作緩動函數?

SVG 的路徑用來描繪平面上的形狀;CSS 緩動曲線則描述兩種進度之間的對應:

  • x 軸:輸入進度,通常是正規化後的經過時間,從開始的 0 到結束的 1。
  • y 軸:輸出進度,用來在動畫屬性的起始值與結束值之間進行插值。

端點固定為 P₀=(0,0) 與 P₃=(1,1)。cubic-bezier(x1, y1, x2, y2) 的引數指定另外兩個控制點 P₁=(x₁,y₁) 與 P₂=(x₂,y₂),共同定義一維函數 y=f(x)。

W3C 已發布的 CSS Easing Functions Level 2 工作草案在 §2.3 說明三次貝茲緩動函數。本文的數值求解範圍是輸入進度 x ∈ [0,1];CSS 也定義了區間外的輸出,依端點側的控制點向外延伸。計算曲線時使用的參數 t 並不是經過時間,而是求出曲線位置的中間變數。

三次貝茲曲線與 Bernstein 基底

三次貝茲曲線由四個控制點決定。當參數 t 介於 0 與 1 之間,曲線上的點 B(t) 為:

B(t) = (1-t)³ P₀ + 3(1-t)² t P₁ + 3(1-t) t² P₂ + t³ P₃

這四個權重就是三次的 Bernstein 基底多項式。由二項式展開可得以下性質:

  • 非負性:在 [0,1] 上,Bᵢ,ₙ(t) ≥ 0。
  • 單位分解(partition of unity):所有權重的總和為 1。
  • 對稱性:Bᵢ,ₙ(t)=Bₙ₋ᵢ,ₙ(1−t)。

權重非負且總和為 1,代表 B(t) 是四個控制點的凸組合,因此曲線位於四點構成的凸包內。這裡必須包含兩個固定端點,不能只看 P₁ 與 P₂。有效的 CSS 曲線中,四點的 x 座標都在 [0,1],所以 x(t) 也不會超出這個區間。

為什麼 x 控制座標必須介於 0 與 1?

端點固定後,x 座標可寫成:

x(t) = 3(1-t)² t · x₁ + 3(1-t) t² · x₂ + t³

若要用曲線將 x 對應到 y,x 座標就不應往回走,否則同一個輸入可能對應到多個曲線參數。對 t 微分可得:

x'(t) = 3[(1-t)² x₁ + 2(1-t)t(x₂-x₁) + t²(1-x₂)]

x₁,x₂ ∈ [0,1] 能保證導數非負,不需要再加上 x₁ ≤ x₂。以下從公式推導:固定 t 後,x'(t)/3 是 x₁、x₂ 的仿射函數,因此在單位正方形內的值,可表示成四個角落值的凸組合:

(x₁, x₂) = (0, 0): x'(t)/3 = t²
(x₁, x₂) = (0, 1): x'(t)/3 = 2t(1-t)
(x₁, x₂) = (1, 0): x'(t)/3 = (1-2t)²
(x₁, x₂) = (1, 1): x'(t)/3 = (1-t)²

四個式子都非負。x(t) 又不是常數多項式,所以它的導數不可能在任何長度大於零的區間內處處為零。因此 x(t) 嚴格遞增,但個別位置的導數仍可能為零。例如 x₁=1、x₂=0 時,t=0.5 的導數就是零,反函數卻依然唯一。

CSS 對 y 控制座標沒有相同的 [0,1] 限制。例如 cubic-bezier(0.68, -0.55, 0.27, 1.55) 可讓輸出低於 0 或高於 1,產生先往反方向移動、再超過目標位置的效果。

反向求解:從時間 x 找到曲線參數 t

瀏覽器需要的是「給定輸入進度 x,求出輸出進度 y」。但參數式直接提供的是 t → (x,y),不能一般性地把經過時間的比例直接代入 t。

  1. 先求出滿足 x(t)=x 的曲線參數 t。
  2. 再把這個 t 代入 y(t),得到輸出進度。

第一步是三次方程式的求根問題。雖然可以使用解析解,實作時也能依精度、計算成本及特殊控制點附近的穩定性,選擇反覆逼近的數值方法。CSS 規範並未要求特定的求根演算法。

牛頓法與二分法:如何安全求出反函數?

牛頓法(Newton–Raphson method)透過下式反覆更新估計值,求解 x(t)−x_target=0:

t_next = t - (x(t) - x_target) / x'(t)

導數太小時,下一個估計值可能跳出 [0,1]。導數為零也不只發生在端點,例如 x₁=1、x₂=0、t=0.5 就是區間內的例子。實作時需檢查殘差、導數、新估計值與迭代次數上限;無法安全使用牛頓法時,可改用二分法。

二分法每次將 t 的候選區間減半,利用 x(t) 的單調性讓根持續留在區間內。相較於牛頓法,通常需要較多次迭代。NanToo 的 cubic-bezier 編輯器對區間內的預覽輸入執行 40 次二分;輸入進度為 0 或 1 時則直接回傳端點。在理想的實數運算下,剩餘區間寬度為 2⁻⁴⁰,但這不代表經過浮點數捨入後的 y 也有相同的精度保證。

編輯器的操作限制與 CSS 語法限制不同。工具會將 x₁/x₂ 限制在 0~1、y₁/y₂ 限制在 −1~2,再將控制座標取到小數點後兩位;輸入進度也限制在 0~1。因此它是有操作範圍限制的預覽工具,並不是用來驗證 CSS 區間外外插的通用求值器。

CSS 標準緩動關鍵字對照

四個 ease 類關鍵字對應到三次貝茲曲線。linear 則是獨立的線性緩動關鍵字,輸出等於輸入;表格最後一列列出具有相同 y=x 輸出的曲線。

表格若超出畫面寬度,可左右捲動。

關鍵字控制座標 (x₁,y₁,x₂,y₂)變化方式
ease(0.25, 0.1, 0.25, 1.0)起步慢,中段加快,結束前放慢
ease-in(0.42, 0, 1.0, 1.0)慢慢起步,逐漸加速
ease-out(0, 0, 0.58, 1.0)快速起步,逐漸減速
ease-in-out(0.42, 0, 0.58, 1.0)對稱的慢起步與慢收尾
linear(0, 0, 1.0, 1.0)等速輸出,效果相同

transition-timing-function 的初始值是 ease。linear 那一列的對角線曲線滿足 x(t)=y(t),但這兩個座標一般不等於 t。也要區分關鍵字 linear 與函數 linear():後者可在多個點之間進行分段線性插值。

單一三次曲線無法任意表達多次彈跳:y'(t) 是二次式,區間內最多只有兩個轉折點。依所需動作,可改用 linear() 的折線近似、多個關鍵影格,或自行用 JavaScript 計算。

字型輪廓也使用貝茲曲線

貝茲曲線不只用來控制動畫時間,也用來描述文字的形狀。

表格若超出畫面寬度,可左右捲動。

輪廓格式曲線次數每段的點數起源
TrueType(Apple/Microsoft,1991)二次3 點:起點、控制點、終點Apple
OpenType CFF/Type 1 輪廓三次4 點:起點、兩個控制點、終點Adobe

TrueType 輪廓採用二次曲線,CFF 與 Type 1 輪廓則採用三次曲線。OpenType 支援這兩種輪廓表示方式。至於光柵化過程內部如何近似或細分曲線,則可能因實作而異。

Horner 法與 de Casteljau 插值法

已知 t 後,可以用不同方式計算曲線座標。第一種是展開多項式,再用 Horner 法求值。對 CSS 固定端點的 x 座標,以下 JavaScript 可計算 x(t):

const a = 3 * x1 - 3 * x2 + 1;
const b = -6 * x1 + 3 * x2;
const c = 3 * x1;
const x = ((a * t + b) * t + c) * t;

預先算好 a、b、c 後,每次計算一個座標需要三次乘法與兩次加法。這個次數不包含係數的計算,也不包含反向求解 x(t) 所需的迭代。

第二種是 de Casteljau 演算法,逐層在相鄰點之間插值。這裡 lerp(A,B,t) 表示 (1−t)A+tB,對每個座標分別運算:

Q0 = lerp(P0, P1, t)
Q1 = lerp(P1, P2, t)
Q2 = lerp(P2, P3, t)
R0 = lerp(Q0, Q1, t)
R1 = lerp(Q1, Q2, t)
B  = lerp(R0, R1, t)

三次曲線需要六次插值,不等於只做六次乘法。舉例來說,即使已算好 1−t,單一座標的 (1-t)*a+t*b 仍需兩次乘法與一次加法。Horner 法的算式簡潔,但實際速度仍取決於實作與執行環境。de Casteljau 法在 [0,1] 內反覆使用凸組合,適合穩定求值;兩種方法都無法完全消除浮點數誤差。

重點整理

  • CSS 以貝茲曲線將輸入進度轉換為輸出進度。
  • 兩端固定在 (0,0) 與 (1,1),四個引數指定另外兩個控制點。
  • x₁,x₂ ∈ [0,1] 能保證反函數唯一,即使 x₁ 大於 x₂ 也成立。
  • CSS 允許 y 控制座標超出 [0,1],藉此表達超過目標的動作。
  • 由 x 反求 t,與已知 t 後計算曲線位置,是兩個不同步驟。
  • 牛頓法需要保護條件;二分法則利用 x 座標的單調性保留含根區間。
  • Bernstein 基底的性質讓曲線留在所有控制點的凸包內,固定端點也必須計入。
  • 四個 ease 類關鍵字對應三次貝茲曲線;linear 是輸出等於輸入的獨立關鍵字。
  • TrueType 與 CFF 字型輪廓分別是二次與三次貝茲曲線的另一種應用。

參考資料與來源

編輯說明

本文使用 AI 協助編輯,並於發布前由編輯確認。內容仍可能包含事實、解讀或時效上的錯誤;進行重要判斷前,請查閱所列的一手資料或官方文件。

相關文章