ADR-0007:主題色相只進識別層——動作、互動、聚焦一律中性
- 狀態:已採用
- 日期:2026-07
背景
多色相主題(v0.3.0 起)讓宿主用 data-color-theme 換一套色相。從那天起,
「主題色相可以出現在哪些介面層」這個問題被重新討論了三次,每次都要重新考古量測數據:
- v0.3.0:
--primary與--brand分家——品牌色偏亮偏飽和,直接當primary會讓高飽和色的出現面積失控。同一輪把--ring從中性改成吃主題色相。 - v0.6.0:石墨(預設主題)照公式生成的近中性 brand,距離「停用」的外觀只有
ΔE00 8.5——brand 按鈕看起來像停用的。修法是承認預設主題沒有品牌色(鏡射 primary),
並加守衛
ΔE00(brand, 停用外觀) ≥ 12。 - 本次:實際使用發現主題色聚焦環會與欄位提醒色撞在同一個輸入框上—— 一格「已改動未送出」的琥珀欄位獲得焦點時,琥珀(語意)與主題紫(焦點) 兩套強調色疊在一起;切到青玉主題又變成琥珀配青綠。同一個畫面元素上的 強調色組合隨主題漂移,聚焦環的用意會被誤讀成另一種提醒。
三次討論、零份正本。這則 ADR 把色相預算一次寫死。
選項
| 選項 | 說明 |
|---|---|
| A. 主題色相可以進元件(ring 維持主題色、brand 按鈕不設限) | 識別感最強,但強調色組合隨主題變,與提醒色的碰撞無法根治 |
| B. 主題色相只進識別層;聚焦環改回中性;brand 按鈕維持有守衛的邊界 | 提醒色的語意空間完全獨立於主題;識別集中在 Layout |
| C. 元件層完全零主題(收掉 brand variant、表面不帶色調) | 規則最簡單,但表面純灰與帶色 Layout 並置會產生「兩套系統拼裝」感(v0.6.0 實測),且識別無處落腳 |
決定
採 B。 色相預算如下:
| 介面層 | 吃主題色相? | 載體 |
|---|---|---|
| Layout 大區塊背景風格色調 | ✅(只轉色相) | 12 個帶色調中性色(--background、--card、--muted、--border…,chroma 0.007–0.023) |
| 選單/選中導覽項/品牌強調 | ✅ | --brand 家族 4 個(brand、brand-foreground、brand-subtle、brand-subtle-foreground) |
| 動作(按鈕) | ❌ | --primary 中性近黑;唯一例外是 Button 的 brand variant(見下) |
| 互動(hover/pressed/已選) | ❌ | currentColor 疊加(6%/14%/20%),機制本身無色相 |
| 聚焦環 | ❌(本次改回) | --ring 回落 :root 中性基礎值,主題層不再覆蓋 |
| 狀態/提醒色 | ❌ | success/warning/info/danger/destructive/edit 全主題不變 |
| 資料(圖表 8 色) | ❌ | 全主題共用 |
主題覆蓋的 token 從 17 個減為 16 個(brand 4 + 帶色調中性 12)。
Button 的 brand variant 是有守衛的邊界例外:只給一頁一顆的非提交型入口,
確認/送出/儲存一律 primary,且守衛盯著 ΔE00(brand, 停用外觀) ≥ 12。
它屬於識別層(「這是誰的產品」),不屬於動作層。
理由
- 提醒色與焦點指示是兩個體系,不能共享色相空間。 欄位提醒色(琥珀=已改動、danger=有問題)與聚焦環會出現在同一個輸入框上。 ring 帶主題色相時,這個組合每換一次主題就變一次;ring 中性之後, 「語意用彩色、焦點用中性」在所有主題下恆成立——色彩語言統一,切主題不會誤讀。
- 色彩疲勞管的是面積 × 頻率,這把尺對 ring 與按鈕給出相反的答案。
按鈕面積大、頻率高,主題色進去會讓換主題等於換整個介面的吵度——所以
primary必須中性。 聚焦環 2px 寬、一次只有一個,主題色在它身上換不到多少識別價值, 卻要付出與提醒色撞色的成本。付出與收益都指向中性。 - 無障礙在這個決定上是中立的,所以不構成反對理由。 聚焦環的門檻是對最亮表面 3:1(WCAG 1.4.11/2.4.7),靠的是亮度差不是色相—— 色覺障礙使用者辨識 ring 從來不靠顏色。中性 ring 對六主題表面實測 20.01:1(淺)/8.54–8.76:1(深),全部遠超門檻。
- 表面帶色調是「主題在 Layout、元件冷靜」能成立的前提,不是違例。 v0.6.0 實測:主色暖綠而表面固定冷藍時,介面有「兩套系統拼裝」感。 表面 token 由 Layout 與元件共用,chroma 壓在 0.023 以下、只轉色相、 L 與對比關係不動——單格不可辨,但讓帶色的 Layout 與中性的元件坐在同一個世界。
影響
generate-theme.mjs不再為主題生成ring;verify-color.mjs改驗 「中性基礎 ring 對每個主題最亮表面 3:1」(同一個 ring、六個對象,逐主題驗)。- 主題宿主的聚焦環外觀改變(主題色 → 中性)。
@dooping/tokensbump minor。 - 元件零行為改動——全部走
ring-ring,值的決定在 token 層。 - 想要「元件連 brand 都沒有」的全中性姿態:用石墨主題,不是改 token。
- 想在確認按鈕上用主題色、或想讓 ring 吃主題色:必須先推翻這則 ADR。
- 每個提醒色的定義、場景與擴充程序見文件站「提醒色辭典」; 色相預算的速查表在「深淺主題 → 色相預算」。