跳至主要內容

開發紀錄

設計 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)