CSS 中的 cubic-bezier() 緩動曲線是由剛好四個數字所定義——x1、y1、x2 和 y2——用來描述固定起點 (0, 0) 與固定終點 (1, 1) 之間的兩個中間控制點。這四個數字會直接寫入 transition-timing-function 或 animation-timing-function 屬性中,用來告訴瀏覽器如何將「經過的時間」對應到「動畫進度」。因為起點和終點永遠不會移動,曲線唯一能改變的就是中間這段旅程的形狀:緩慢的開始、俐落的收尾、平順的減速、衝過終點的過衝,或是動畫開始前向後拉回的尖銳蓄勢。從大家熟悉的 ease 關鍵字到自訂的類彈簧動效果,所有 CSS 中的視覺緩動風格,都只是這四個座標的不同選擇而已。因此 cubic-bezier() 函式可說是前端開發者用來調整 UI 元件動感時,最精準的一把利器。
在實際操作曲線之前,兩個參考資料是必備的。第一個是 W3C 的 CSS Easing Functions Level 1 規範,當中定義了語法、有效性規則以及關鍵字的對應方式。第二個是 MDN 上 cubic-bezier() 的頁面,其中記錄了瀏覽器的實際行為並提供實用範例。這兩份資料在所有會影響你輸入的四個數字的細節上都是一致的。

深入了解 Cubic Bezier 緩動函式
CSS 中的 cubic Bézier 曲線是一條由四個點描繪而成的參數曲線。其中兩個點——(0, 0) 和 (1, 1)——永遠固定不動,分別代表動畫開始的那一刻(時間為零、進度為零),以及動畫結束的那一刻(時間為滿、進度為滿)。剩下的兩個點——(x1, y1) 和 (x2, y2)——就是你傳給 cubic-bezier() 的參數值,它們會把曲線從一條直線拉開。
視覺上,這兩個控制點的作用就像磁鐵一般。控制點往左上角拉,數值就會起步快速、再逐漸緩和。控制點往右下角拉,數值就會起步緩慢、再逐漸加速。兩個方向相反的控制點則會形成一條中間平緩、兩端尖銳的 S 形曲線。由於實際上只有各控制點的 y 座標會改變動畫的進度,緩動的視覺故事基本上就是 y1 與 y2 的故事。
四個控制點及其限制
CSS Easing Functions Level 1 規範對 x 值要求嚴格、對 y 值則較為寬鬆。兩個 x 座標都必須落在閉區間 [0, 1] 內——超出這個範圍會讓 cubic-bezier() 的值失效,瀏覽器將會回退為預設值。然而 y 座標可以是任何有限的數字,包括負值以及大於 1 的值。負的 y 會產生蓄勢效果(動畫數值看起來會先往回拉再往前進),y 大於 1 則會產生過衝(數值會超過目標位置,然後再回穩)。
五個標準的緩動關鍵字都對應到同一份規範中定義的特定 cubic-bezier() 值。下表記錄了這些標準的控制點,讓關鍵字與曲線之間的關係便於查驗。
| CSS 關鍵字 | x1 | y1 | x2 | y2 | 常見感受 |
|---|---|---|---|---|---|
| linear | 0 | 0 | 1 | 1 | 從頭到尾等速 |
| ease | 0.25 | 0.1 | 0.25 | 1 | 起步平順,結尾柔和(預設值) |
| ease-in | 0.42 | 0 | 1 | 1 | 起步緩慢,結尾加速 |
| ease-out | 0 | 0 | 0.58 | 1 | 起步快速,結尾減速 |
| ease-in-out | 0.42 | 0 | 0.58 | 1 | 兩端對稱緩慢,中間快速 |
這些對應關係是規範的一部分,因此任何聲稱相容 CSS 的產生器都必須與之完全一致。CSS Cubic Bezier 產生器將這些作為參考資料:選擇某個關鍵字就會載入相同的控制點,而且顯示出來的宣告永遠會列出完整的四個數字,而不是隱藏起來的關鍵字。
使用產生器設計曲線
最快找到可用 cubic-bezier() 值的方法,就是即時看著畫面回饋來調整這四個控制數字。以下的操作流程是直接在瀏覽器分頁中使用 CSS Cubic Bezier 產生器。
- 開啟產生器並選擇起點。如果你已經知道自己想要類似某個標準關鍵字的感受,就點選該關鍵字按鈕來載入它對應的控制點。如果你是從零開始,則可以先保留輸入欄為任何合理的預設值。
- 調整四個控制數字。輸入或拖曳 x1、y1、x2 和 y2,讓曲線接近你想要的形狀。請記得規範中的規則:x1 和 x2 必須維持在 0 到 1 之間,而 y1 和 y2 的範圍可以是 −10 到 10。數字會在你輸入的同時即時更新。
- 檢視圖表。方形圖表會把從左下固定起點到右上固定終點的參數曲線畫出來。超出方框的曲線代表 y 值產生了過衝或蓄勢效果,這可能是刻意設計的。
- 讀取範例數值表。數值表會顯示在輸入時間 0、0.25、0.5、0.75 和 1 時的動畫進度。利用它來確認在四分之一、二分之一、四分之三這些時間點上,曲線是否大致符合你預期的形狀。
- 播放動畫預覽。切換「run preview」來讓一個圓形以目前的曲線,在 900 毫秒內水平移動。重複點擊以便在相同的緩動下比較正向與反向的運動。
- 複製完整的宣告。使用「copy CSS」按鈕將 transition-timing-function: cubic-bezier(...); 寫到剪貼簿。宣告本身已經包含分號,因此可以直接貼進樣式表中。
- 在實際元件中測試緩動效果。把宣告放進你正在撰寫的實際 transition 或 animation 中,搭配真實的屬性、移動距離和持續時間。若動感不對,就回到步驟 2 再次微調。
解讀範例數值表與動畫預覽
數值表回答了一個單看曲線圖無法回答的問題:當一段固定比例的時間過去後,動畫的數值實際上推進了多少?對於每一個輸入時間,求解器會找出曲線參數中 x 座標符合該時間的位置,然後計算在該參數下的 y 座標。這個區分很重要,因為 CSS 動畫是以輸入時間而非曲線參數在跑的。一條 x 控制點偏離的曲線,並不會把一半的動感放在一半時間點的位置上。
動畫預覽會使用同一條計算出的曲線,套用在一段 900 毫秒的水平 transition 上。預覽展示的是時間節奏,而不是實際執行效能。真實元件一旦屬性、距離、持續時間、繪製成本或輸入裝置改變,感受可能會不同。請用預覽來比較不同曲線之間的差異,並確認動感的大致形狀,接著在實際元件上驗證後再上線。
若曲線刻意延伸到可見方框之外,圖表並不代表數值被夾在範圍內。方框會固定在零到一的框線內,讓一般曲線易於比較。數值表和移動中的圓形都會使用實際計算出來的緩動值,因此過衝在數值表中仍會以大於 1 的 y 值呈現,在預覽中也會看到圓形短暫落在目標位置之外。
在實際 Transition 中套用時間函式
當預覽中的曲線感受已經滿意後,把宣告貼進正式環境的樣式表。cubic-bezier() 值會用在 transition-timing-function(用於狀態轉換)以及 animation-timing-function(用於關鍵影格動畫)中。常見的寫法如下:
transition: transform 350ms cubic-bezier(0.22, 0.61, 0.36, 1);
這一行就把屬性、持續時間和緩動一次設定完成。產生器並不會產生完整的 transition 簡寫、持續時間、延遲,或是其他動畫相關的部分。這些值仍然由你掌控,這是刻意的設計:即使是同一條曲線,16 像素的滑動與 400 像素的滑動,適合的持續時間通常並不相同。
在關鍵影格動畫中,同樣的值可以用於 animation-timing-function。緩動會套用在每一對關鍵影格之間,這可能會產生與單一 transition 相當不同的動感。在動畫上使用自訂曲線時,請預覽整個循環,而不是只看第一段。
過衝、減少動效果與實用曲線
語法上有效的 CSS 並不自動代表合適的 CSS。帶有強烈過衝的 cubic-bezier() 可能會讓按鈕看起來像從容器邊界彈開、面板短暫滑出,或暴露出原本預期要保持裁切的內容。當動感本身帶有意義——例如確認點擊、表示完成、傳達狀態——過多的過衝會削弱這個訊息。當動感只是裝飾時,過衝可能視情境而顯得討喜,也可能讓人分心。
請尊重使用者減少動效果的偏好。prefers-reduced-motion 媒體查詢可以把自訂緩動切換回 linear,或縮成一段非常短的 transition,讓狀態變更不需大幅移動也能被理解。一條有效的曲線並不自動代表無障礙、效能良好或合適,只能代表它在數值上是完整正確的。
另外還有兩個實務上的限制要記得。產生器會把 x 輸入限制在閉區間 [0, 1],並接受介於 −10 到 10 之間的有限 y 值;底層計算會在產生輸出前再次獨立驗證這些限制。數字只有在宣告被序列化為文字時才會被四捨五入到小數三位;在瀏覽器內的計算仍保有完整的 JavaScript 精度。所有計算都在本機進行,沒有任何曲線值、宣告或互動資料會被上傳到任何動畫服務,因此這個工具可用於內部機密的設計規格與內部的色彩系統上。
若你正在比較不同選項,CSS Create Toggle Button With Exact Geometry 對此有詳細說明。
若你正在比較不同選項,CSS Gradient Colors: From Stops to Production-Ready Code 對此有詳細說明。