EN 中文
← 回文章列表
Side Project · CSS

同一個 CSS bug 出貨了三次,因為修好一次沒有修好那個比例

一個圓角膠囊卡在另一個圓角容器裡,兩條曲線之間需要真正的間距,不然內層形狀會明顯戳出外層邊框。修過一次、又在別處修過一次,結果在同一個已經修好過的元件的新尺寸變體裡,又出貨了第三次。

2026-07-22 myps6415
3 次
這個 bug 出貨的次數
p-1 → p-1.5
每一次的修法都一樣
1 天
從出貨到使用者抓到第三次發生

背景

bopomofokids.com 整個視覺風格是一套刻意設計的系統 ——每個元素都有粗粗的墨色邊框、硬邊偏移陰影,完全不用模糊。按鈕跟膠囊一律是 完全圓角(rounded-full)。這套系統裡有一個一再出現的元件:分段控制項——一個 rounded-full 的彩色膠囊代表目前選中的選項,滑動在另一個更大的 rounded-full 容器裡——用在頁首的語言切換、設定面板的各種開關,以及某個模式自己的遊戲內速度 切換器上。

這個模式有一個從 class name 看不出來的幾何問題,只有真的去看渲染結果才會發現。

為什麼兩層完全圓角需要真正的間距

這不是一個可以設一次就一勞永逸的固定像素值——它是外層 padding 跟內層膠囊實際 渲染高度之間的一個比例,而膠囊的渲染高度又取決於字級、行高,以及標籤文字 本身需要多少空間。

前兩次

這個 bug 分別獨立在兩個不同的元件裡出貨:頁首/設定面板用的 Segmented 元件 (當時是 p-1),以及 BalloonMode 自己的遊戲內速度切換器(當時是 p-1.5)。 兩者都用同一種方式修好——加大 padding——分別落在 p-1.5p-2。兩個不同的 元件、兩次獨立的修法,但根本原因是同一個。

第三次——發生在一個已經修好過的元件裡

Segmented 後來為了頁首更精簡的切換介面,新增了 smxs 兩個尺寸變體,是 2026-07-20 那次版面重新設計的一部分。這兩個新變體都複製了已經修好的 md 變體 的邊框寬度,但 padding 卻退回了 p-1:

const SIZES = {
md: { box: 'border-3 p-1.5 gap-1', option: 'px-2.5 py-1.5 text-xs' },
sm: { box: 'border-3 p-1   gap-1', option: 'px-2   py-1   text-[11px]' }, // ← 同一個 bug,又回來了
xs: { box: 'border-2 p-1   gap-0.5', option: 'px-1.5 py-0.5 text-[10px]' }, // ← 同一個 bug,又回來了
};
      App.tsx — Segmented 尺寸變體,第三次修法之前
    

同一個元件、同一個邊框寬度、md 尺寸已經出貨過一次的修法——結果一模一樣的 bug 又在兩個新尺寸變體裡重現了一次,因為已經上線的那次修法,只動到了當時存在的那 一個尺寸變體。這次是隔天就被使用者的一張語言切換介面截圖抓到,修法也一樣: 把兩個新變體的 padding 從 p-1 加到 p-1.5

const SIZES = {
md: { box: 'border-3 p-1.5 gap-1', option: 'px-2.5 py-1.5 text-xs' },
sm: { box: 'border-3 p-1.5 gap-1', option: 'px-2   py-1   text-[11px]' },
xs: { box: 'border-2 p-1.5 gap-0.5', option: 'px-1.5 py-0.5 text-[10px]' },
};
      App.tsx — Segmented 尺寸變體,第三次修法之後
    

為什麼英文標籤讓情況更糟

這個 App 的語言切換可以顯示「中文|EN」,或是切到英文介面文案時的對應版本,而 英文標籤通常比旁邊的中文更高更寬——同樣的視覺份量需要更多行高。這在完全沒有 改動任何 padding 數值的情況下,進一步壓縮了實際間距:同一組數字 padding,一旦 膠囊裡的標籤需要更多垂直空間,實際留下的空隙就變少了。一個在中文下隨便一瞄 沒事的控制項,在完全相同的 CSS 數值下,切到英文可能就出事。

這次學到什麼

這是一個比例的性質,不是『這個元件』整體的性質

修好 Segmentedmd 變體,並沒有修好 Segmented——它只修好了一個特定的 邊框寬度對 padding 比例。smxs 實質上是恰好共用一個名字跟一個檔案的 新元件。每一個巢狀膠囊控制項的新尺寸變體,都需要自己的間距檢查;在同一個檔案 裡別處錯過一次,不代表新的變體就對這個問題免疫。

內容長度會改變幾何,即使 CSS 完全沒變

同一個 padding 數值,渲染出來的實際間距會因為膠囊裡標籤需要多高而不同——這又 取決於語言、字型、文字長度。一個在某種語言的文案下看起來沒事的控制項,在真的 檢查過它實際上會出貨的每一種語言之前,都不算證明沒事。

這類渲染 bug 需要盯著實際像素看,不能只看 class 清單

光讀 Tailwind 的 class,p-1p-1.5 看起來都不像明顯有問題——這個 bug 只 存在於渲染出來的幾何裡。新增或調整任何巢狀膠囊控制項時,真正能抓到這個問題的 做法,是對實際輸出、以它真正的像素尺寸截圖(而不是在開發伺服器上 100% 縮放 隨便看一眼),而且這件事要對每一個新變體都做一次,不是對整個元件做一次就算數。