有效的 CSS cubic-bezier 緩動曲線是由剛好四個控制座標所定義的 —— x1、y1、x2、y2 —— 只要任何一個 x 值落在閉區間 [0, 1] 之外,CSS 就會立刻讓該宣告失效。這條單一規則正是大多數 cubic-bezier 產生錯誤的根源:瀏覽器會靜默忽略該函式,動畫以預設的 ease 時間軸執行,而開發者則誤以為曲線已生效。再加上以下事實:當 x 控制點被橫向拉扯時,曲線參數 t 並不等於經過的時間;y 軸可以表達圖表無法顯示的 overshoot;而有效的曲線並不自動代表具有可存取性——你手上就有一份預設情況下沒有任何視覺編輯器會提醒你的細微失敗模式清單。CSS Cubic Bezier 產生器將每一個失敗模式都揭露為可檢視的物件 —— 一個受限的 x 輸入、一個 Newton 加二分法的求解器、一個數值取樣表,以及一個 900 毫秒的動態 transform 預覽 —— 讓你在宣告進入正式環境之前就能先抓到問題。

CSS Cubic-Bezier 產生過程中悄悄失敗的六種方式
Cubic-bezier 的產生看似簡單 —— 選四個數字、貼上宣告、觀察動畫執行。CSS 規範精確地定義了這個值,但大多數編輯器把規則藏在友善的滑桿和具名預設值背後。結果就是一個產生流程,其中每個錯誤在技術上看起來都「有效」,卻會產生飄移、肉眼看不到 overshoot,或在沒有任何 console 警告的情況下退回預設 ease 的動畫。幾乎所有靜默失敗都來自六種模式。只要你知道該往哪裡看,每一種都能被偵測到;而只要有正確的檢視介面,每一種也都能預防。
下面各節依照錯誤通常出現的順序逐一說明:首先是瀏覽器靜默強制執行的 x 座標限制,接著是 50% 取樣處的混淆,然後是圖表外框的錯覺,再來是關鍵字與數字之間的不一致、預覽的限制,最後是 CSS 有效性與動畫可存取性之間的落差。文末有一段簡短的 how-to,展示位於 /color/css-cubic-bezier/ 的產生器如何在你把宣告送進正式環境之前,先將上述每一項風險攤開來檢視。至於底層規範,W3C CSS Easing Functions Level 1 文件是權威參考;MDN 的 cubic-bezier() 頁面則涵蓋瀏覽器行為與操作範例。
讓 x1 或 x2 滑出 [0, 1] 範圍
第一個錯誤既是最容易犯,也是傷害最大的。只要任何一個 x 控制座標落在閉區間 [0, 1] 之外,CSS 就會立刻將該 cubic-bezier 值視為無效,因為 x 代表的是輸入時間的位置。瀏覽器不會警告、不會記錄、也不會拋出例外 —— 它只會直接忽略該時間函式並退回 ease。一個只短暫測試動畫的開發者會看到畫面有動,於是假設曲線已套用,結果上線的轉場在每一次狀態變化時其實都用了錯誤的緩動。
可靠的防禦方式是在源頭就限制 x 的輸入。CSS Cubic Bezier 產生器在介面中就把 x1 與 x2 限制在 CSS 有效的範圍內,接著在輸出序列化宣告之前,再對 y 值與 x 範圍執行一次獨立的驗證程序。如果你手動建立曲線,規則也一樣:任何超出 [0, 1] 的 x 值都保證該曲線不會照寫的那樣執行。把 x 限制視為硬性的上下界,而不是軟性的建議。
把 50% 取樣誤讀為曲線的一半
第二個錯誤來自於把曲線參數 t 與瀏覽器實際推進的經過時間混為一談。CSS 時間函式以 x 軸作為輸入進度、以 y 軸作為輸出進度。當控制 x 座標是對稱的時候 —— 例如 0.25 與 0.75 —— 曲線在 t = 0.5 時剛好會讀作「一半」。當控制 x 座標被橫向拉扯,這個關係就會破壞。
這正是表格化取樣資料存在的目的,用以避免這個錯誤。CSS Cubic Bezier 產生器在經過時間 0、0.25、0.5、0.75 與 1 取五個點 —— 方式是對曲線求解,找出 x 座標符合所要求輸入的參數,再評估該參數下的 y 值。求解器使用有界牛頓法迭代,必要時再用二分法收尾,這正是處理非均勻 x 間距所需要的同一套做法。只能畫出幾何路徑的曲線預覽,無法告訴你在中點動畫值到底推進了多少;只有取樣表能做到。
相信圖表外框而不是取樣資料
用肉眼判讀圖表是第三個常見錯誤。產生器中的方形圖表維持穩定的 0 到 1 外框,讓一般時間曲線保持視覺上的可比較性。那個外框是一個視窗,而不是夾鉗。y 控制值為 1.6 在 CSS 中完全有效 —— 它會產生 60% 的 overshoot —— 但產生的曲線在抵達該峰值途中會超出圖表頂端。如果你看到曲線跑出外框,自然的反應是該值已被裁剪,但實際上並沒有:實際的緩動仍會上升到 1.6,預覽元素仍會走那麼遠,取樣表在取樣的 x 處仍會回報真實的 y 值。
實務上的原則是:用圖表做形狀比較,用取樣表取得數值真相。當 overshoot 對設計至關重要時 —— 例如按鈕彈跳、通知滑入、拖曳釋放後的回穩 —— 直接讀取 0.25、0.5 與 0.75 那幾列。如果那些取樣值都維持在標準 ease 區帶附近,不論圖表外框看起來多戲劇化,你的動畫都會被讀成一般的轉場。若想進一步深入同一個限制在 y 軸那一側的細節,y 值超出 0–1 範圍這篇文章涵蓋了規範規則與其實際影響。
在需要數字的地方複製了關鍵字
第四個錯誤是文件方面的落差。五個標準的 CSS 緩動關鍵字 —— linear、ease、ease-in、ease-out、ease-in-out —— 各自對應到 W3C CSS Easing Functions Level 1 規範所定義的特定控制座標。許多設計師之所以選用關鍵字,是因為它能表達意圖(「這應該要感覺像 ease-in-out」),接著把它貼進樣式表,而團隊之後又想微調曲線。微調一個關鍵字意味著必須把它換成一個完全不同的緩動,而不是調整某個數字,原始意圖於是再也無法從檔案中被重現。
CSS Cubic Bezier 產生器透過在輸出宣告中永遠暴露完整的四個數字來解決這個問題,即使你是從關鍵字按鈕開始。Linear 會變成 cubic-bezier(0, 0, 1, 1)。ease-in-out 會變成 cubic-bezier(0.42, 0, 0.58, 1)。數字會以三位小數序列化以便閱讀,而底層計算則維持完整的 JavaScript 精度。結果是一段既能記錄曲線實際內容、能在程式碼審查中被 diff、又能在不失原預設身分的情況下以手動方式修改的宣告。
相信單一的 900 毫秒 transform 預覽
第五個錯誤是把動態預覽當成真實動畫的替代品。預覽使用 900 毫秒的 transform 轉場以及精準產生的緩動字串,讓圓形在兩個水平位置之間切換。這是時間上的精確示範,但它並不是正式環境行為的量測。轉場的實際感受會隨著被動畫化的屬性、移動的距離、選擇的持續時間、渲染成本、輸入裝置,以及介面中周遭的動畫而改變。
在 96 像素的滑動上看起來平靜的曲線,套到 400 像素的抽屜上可能會顯得躁動。適合 900 毫秒 transform 的時間函式,套到 200 毫秒的透明度淡入淡出上可能會顯得遲鈍。誠實的工作流程是:把宣告複製出來,放到真實元件中,搭配真實的屬性、真實的距離與真實的持續時間,然後在那裡觀察動畫。重複點擊預覽也能用來比較正向與反向的動態;即使數字看起來平衡,曲線在感受上不一定是對稱的。
把「有效」與「合適」混為一談
第六個錯誤是最容易被忽略的,因為 CSS 本身並不強制這點。一個 cubic-bezier 值在技術上可以是有效的 —— 每個座標都在 CSS 定義的規則之內 —— 但對該介面來說仍是糟糕的選擇。超過 1 的大幅 overshoot 會讓控制項看起來像是反方向移動、跑出容器,或露出原本預期要保持裁切的內容。零與一之間的快速振盪會產生對前庭敏感的使用者來說不悅的動畫。使用大幅度彈跳來動畫的聚焦環,可能會讓鍵盤使用者感到迷失。
有效性是地板,而不是天花板。在確認宣告有效之後,還需要額外檢查:動畫是否保持在容器內;是否尊重已選擇關閉動畫使用者的 prefers-reduced-motion;元素正在轉場時,聚焦行為是否仍然可預測;該動畫是否能單獨不依賴動作就傳達預期的狀態變更。產生器刻意只專注於單一的 cubic-bezier 時間函式,讓其輸出保持可預測,但圍繞著可存取且高效能動畫的責任,仍然落在實際交付元件的開發者身上。
在不犯這些錯誤的情況下產生 Cubic Bezier 曲線
- 開啟 CSS Cubic Bezier 產生器,如果你想要一條已知良好的參考曲線(linear、ease、ease-in、ease-out、ease-in-out),就從關鍵字按鈕開始。
- 拖曳控制點來調整 x1 與 x2;輸入被限制在 [0, 1] 範圍內,所以超出範圍的值無法抵達輸出。
- 調整 y1 與 y2 以塑造輸出形狀;當你想要 anticipation(負 y)或 overshoot(y 大於 1)時,可以讓它們超出 [0, 1] 範圍;系統接受介於負十到十之間的有限值。
- 讀取在經過時間 0、0.25、0.5、0.75 與 1 的五列取樣表,確認輸出進度符合你預期的動態。
- 點擊 Run 觀看 900 毫秒的 transform 預覽,透過重複點擊來比較正向與反向的動態。
- 複製完整的宣告,包含結尾的分號,然後貼到真實元件中,搭配真實的屬性、距離與持續時間。
- 在實際介面中測試結果,驗證在 reduced motion 下的行為,並確認在轉場執行期間,聚焦與指標狀態仍維持可預測。
At a Glance: Mistake, Symptom, Fix
| Mistake | Symptom | Fix |
|---|---|---|
| x1 or x2 outside [0, 1] | Animation runs but timing silently falls back to ease | Constrain x inputs at the source; treat the range as a hard limit |
| Reading the 50% sample as halfway through the curve | Output progress drifts away from the expected midpoint | Sample the table; verify x and y at each input |
| Assuming the chart frame clamps output | Curve appears to stop at the edge of the chart | Trust sample values; treat the chart as a window, not a clamp |
| Using a keyword where numbers are needed | Original curve intent is lost once tweaked | Serialize all four numbers; preserve the preset identity |
| Trusting the 900 ms transform preview alone | Motion feels different in production | Test in the real component with real property and duration |
| Treating valid CSS as appropriate motion | Overshoots break layout, accessibility, or focus | Verify reduced motion, focus, and container fit before shipping |
Each of those failures is preventable once you know it exists. The hardest part is that none of them surface as an error message — they appear as motion that feels off, designers who cannot reproduce a curve, or components that quietly use the default ease when the stylesheet says otherwise. Treating the four coordinates as a contract (x bounded by the timeline, y free to express shape, sampling done by x not by parameter, and validity checked before shipping) is the cleanest way to keep generation deterministic.
If you're weighing options, Common CSS Toggle Switch Mistakes in Color and Geometry covers this in detail.