開發紀錄
設計 token 不只是色碼表:先分清楚每個顏色的責任
從本站的背景、卡片、文字與行動色,整理色彩角色、元件庫語意映射和互動狀態,避免換配色時只做全域色碼取代。
- 設計 token
- Tailwind CSS
- 色彩
- 元件設計
把色碼集中成幾個變數,還沒有決定這些顏色應該用在哪裡。如果背景、卡片、hover 和主要按鈕都共用同一個名字,下一次調色時,仍然不知道改一個值會動到什麼。
我比較在意的是角色:這個顏色是在分出內容表面、提供可讀文字,還是讓人找到下一個動作?先有這份分工,token 才能幫助維護,而不只是讓色碼換個地方存放。
以下依據本站在 2026 年 10 月 24 日的共用色彩與元件使用方式整理。這是目前網站的設計取捨,不是一套適用所有產品的標準配色。
名稱要能說出用途,不只描述長相
本站把頁面背景與一般內容表面分開:siteBg 用於頁面底色,siteSurface 用於內容卡片;文字、深色焦點表面與深色表面的前景,也各有自己的角色。
其中一部分可以這樣讀:
| 角色 | 目前色碼 | 主要責任 |
|---|---|---|
siteBg |
#F1F1F0 |
頁面背景 |
siteSurface |
#FCFBF9 |
一般內容表面 |
siteText |
#25272C |
淺色表面上的主要文字 |
siteInk |
#25272C |
深色焦點表面或控制 |
siteOnInk |
#FBFAF7 |
深色表面上的淺色前景 |
siteAction |
#C13F1B |
主要行動控制的填色 |
siteText 和 siteInk 現在雖然是同一個色碼,責任卻不同。一個是文字,一個是表面;若之後需要分開調整,呼叫端不必先猜哪一處黑色代表哪一種用途。
這不代表每種 CSS 屬性都需要一個 token。只有在用途、搭配或未來變動的責任不同時,分開命名才有意義;把同一個責任切成很多近似名稱,也會讓人難以選擇。
文字強調色,不必等於按鈕填色
本站的 primary 是較深的 #A93618,主要行動控制則使用 siteAction 的 #C13F1B。Button 的預設 variant 明確配上 siteOnInk 前景,hover 另使用 siteActionHover。
這個差別不是為了多保留一種橘色,而是讓兩種工作可以獨立調整:一種要在淺色背景上當文字讀,另一種要成為有前景文字的控制表面。只保留一個叫「品牌橘」的 token,往往會把這兩個問題綁在一起。
顏色也必須成對看。W3C 對文字對比的說明,檢查的是文字及其背景之間的關係,不是某一個色碼本身能不能被稱為「可讀」。[4] 同一種橘色放在霧白、炭黑或半透明圖像上,不能直接沿用同一份判斷。
因此,token 的語意命名不會自動帶來對比合規。仍要確認實際前景、背景、字級與狀態;disabled、hover、focus 也不能只檢查其中一張靜態截圖。
元件庫的語意,接回網站已有的角色
網站不一定和元件庫使用同一套名稱。本站保留自己的 siteSurface、siteText 等角色,再把元件需要的 card、popover、foreground 等名稱映射回來。
將目前其中一小段摘出,像這樣:
@theme inline {
--color-background: var(--color-siteBg);
--color-foreground: var(--color-siteText);
--color-card: var(--color-siteSurface);
--color-card-foreground: var(--color-siteText);
--color-popover: var(--color-siteSurface);
}
這裡省略了其他語意色彩,不是一份可直接取代全部樣式的完整設定。重點是相同的卡片角色仍由同一份網站定義供應,不因為多了元件庫,就在另一個地方重新決定它是什麼白色。
Tailwind CSS 把 @theme 變數用來定義可用的 utility;當 theme 變數引用其他變數時,官方文件另外說明了 inline 的處理方式。[3] 在這個例子裡,它是既有角色接到 utility 的技術邊界,不是另外啟動一套網站主題。
但映射也不表示元件可以完全不看自己的 variants。本站 Button 的預設底色直接引用 siteAction,並不是看到某個元件庫的 primary 名稱,就推定所有主要按鈕都使用相同色碼。
Hover 要表達互動,不一定要換掉整張卡片
本站一般筆記卡片維持霧白表面,hover 與 focus-within 用微幅上浮、陰影,以及標題或箭頭的局部強調表示狀態。它沒有在每次指向時,把一般卡片都翻成深色焦點。
深色卡片另有對應的 siteOnInk、siteOnInkMuted 與 siteOnInkAccent。這讓「原本就是焦點內容」和「現在可以互動」不必共用同一種大幅換色訊號。
這是本站目前的視覺層級選擇,不代表按鈕、選取項目或所有控制都應維持透明底。控制需要讓人辨認可操作、選取與停用狀態;應依功能分別決定,不把卡片的 hover 規則套到整個介面。
鍵盤焦點也需要自己的明確提示,不能只借用滑鼠 hover。即使兩者共用某些色彩,出現條件與辨識需求仍然不同。
換配色時,沿角色追查,不做盲目的全域取代
假設想把主要行動色調整得更醒目,我會先找 siteAction 的使用點,再確認按鈕的前景、hover、選取文字與其他引用位置,而不是把整個專案裡相同的十六進位色碼全部換掉。
相反地,若想改一般卡片的閱讀表面,應回到 siteSurface 和對應的文字角色。不能因為畫面上剛好有幾塊相近的白色,就認定它們都應該一起改。
本站也保留獨立命名的產品介面示意色彩。這些是另一種呈現情境,不代表正式產品的所有配色,也不應為了讓網站 token 看起來只剩幾種顏色,就一併抹成網站的行動色。
實際檢查時,先確認改動影響了哪些元件與狀態,再看輸出的 CSS 和瀏覽器中的真實搭配。導入與維護本地 UI 元件仍有另外的責任:token 集中不會自動保住 props、HTML 語意或開關行為。
這篇沒有全站每個狀態的對比量測、視覺驗收或維護成本數據。它提供的是一份改色時能追查的分工:先知道要改哪個角色,再確認受影響的組合,而不是讓一個新色碼替整個設計做決定。
Sources
[3] https://tailwindcss.com/docs/theme — Tailwind CSS — Theme variables [4] https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html — W3C — Understanding SC 1.4.3 Contrast (Minimum)