建立 Token 系統快速新增不同主題
我的角色
Product Designer · DS Owner
團隊
1 PD · 2 RD (iOS, Android)
- 專案背景
- Dark Mode 是連年客服盤點使用者請求的前三名,排入 2025 年度要開發的新功能。但 iOS、Android、Figma 各自維護一套命名,再加一個主題會讓維護更複雜。
- 結果
- 後測滿意度 4.5 / 5,D7 功能留存 93–94%。
- 交付期間
- 2025-06-16 ~ 2025-07-06
4.5 / 5
後測滿意度
93–94%
D7 功能留存率
2 週
交付期
專案背景
Dark Mode 是連年客服盤點使用者請求的前三名,排入 2025 年度要開發的新功能。
產品現狀:iOS、Android、Figma 各自維護一套命名。三個平台分別又混合了多種不同的命名邏輯,有些名字描述外觀,例如 gray3、offWhite。有些名字描述元件,例如 primaryButton。完全沒有規則決定什麼情況該用哪一種。
| 色碼 | iOS | Android | Figma |
|---|---|---|---|
#FCC35D | primaryYellow | yellow_accent | Yellow/Base |
#FFFFFF | mainBg | background_main | Background/Primary |
#E9683F | alertRed | error_color | Red/500 |
#00BA86 | successGreen | green_500 | Green/600 |
#FD9728 | warningOrange | orange_500 | Orange/500 |
色彩並不是會隨意修改的元素,現況雖難以維護但結構還算單純所以堪用,不過一旦要加第二個主題時,沒有系統的管理這些命名問題就會變得很明顯:一個元件要改顏色的時候,要怎麼快速找到對應的名稱、一次改動不同主題的色碼?
真正要解的不是「Dark Mode 要長什麼樣」,而是「主題本身要怎麼被管理」。
核心頁優先,細節頁延後
兩週時程不可能把所有頁面都做進來。團隊把範圍收斂在使用者最常進入的頁面(設定頁、主要頁),把長尾細節頁面延後。
設計規劃
Token 分層:基礎層給設計師管理源頭、語意層讓產品使用
Token 分成兩層,但設計師跟工程師實際使用的是同一層。
- Semantic:設計跟程式端元件實際在使用的 Token。
- Primitive:是語意層顏色的源頭色盤,元件顏色不直接使用。設計師只在「創建色盤」的時候才會動到它,其餘時間基本上不會動用到這個色盤。
切分成兩層的好處是,任何顏色變動都只發生在同一個地方。換主題的時候,改的是 Semantic 對應到哪個 Primitive;調品牌色或做無障礙微調的時候,改的是 Primitive 本身的值,所有引用它的 Semantic 都會跟著更新。不管哪一種,Figma 組件跟 code 都不用動名稱,只需要調整色碼。
primary
LightYellow.600#FCC35DDarkYellow.600#FCC35Dsurface
LightNeutral.50#FFFFFFDarkNeutral.900#212121error
LightRed.500#E9683FDarkRed.400#F77C56success
LightGreen.600#00BA86DarkGreen.500#00C28Chighlight
LightOrange.500#FD9728DarkOrange.400#EB8A1B
不分模式的命名,只改值不改名
Semantic 名字裡不會出現 light 或 dark 字樣。名字描述的是「在系統中的角色」,不是「在哪個模式下長什麼樣」。Spec 把這件事寫成兩條硬性規則。
- Light 跟 Dark 必須使用同一個 token 名字。
- 切換 mode 改的是值,不是名字。
code 引用的那一行一直一樣,在 Light 時解析到 Light 的值,在 Dark 時解析到 Dark 的值,使用端永遠只寫一行。以後加第三、第四個 theme(high-contrast、brand theme、accessibility)的時候,不用改名,也不用整個 codebase 找替換。
用 camelCase 當命名規則
Token name 採用 camelCase。當時討論過 kebab-case 跟 snake_case,最後選 camelCase 有兩個理由。
- 平台兼容性。 iOS(Swift、Objective-C)和 Android(Kotlin、XML)都能讀通同一份名字,不需要做平台轉換。
- 穩定性。 snake_case 在 Swift 不慣用,kebab-case 在多數語言不能直接當變數名,camelCase 是三方都不彆扭的最大公約數。
整理 color token spec
所有 token 名稱、Light 跟 Dark 對應值、用途定義,都集中在一份跨平台共用的 spec。這份 spec 裡面也包含了名稱、色碼「舊對新」的資訊,方便 RD 做替換。上面也整理 color token 的使用原則,如果有人必須使用到 Primitive token,那就是「該補新 Semantic token」的訊號,那就會開啟更新的流程。
Dark Mode 是一個讓我們能夠重新聚焦 Light Mode 那些沒處理好的設計結構的機會。
顏色針對飽和度跟亮度重新平衡,不直接用相同色碼。如果直接沿用,Light 的錯誤紅放到 Dark 背景上會過度飽和、看起來很刺眼。所以每個 Dark 對應值都挑選往色盤下一階的顏色。調整一下亮度、飽和度,保留顏色的語意,紅依然代表錯誤,綠依然代表成功。
- error#E9683F
- success#00BA86
- highlight#FD9728
結果
後測 Survey 拿到 4.5 / 5
總回覆 685 份
5 星
501 (73.14%)
4 星
107 (15.62%)
3 星
41 (5.99%)
2 星
8 (1.17%)
1 星
28 (4.09%)
後測 Survey 收到 685 份回覆,平均 4.5 / 5 stars。5+4 星合計 88.76%。
「I get a lot of glare from white backgrounds, so this is much easier for me to see.」 · 「I do like it because I use black screen to save on battery life.」 · 「Ficou incrível e confortável ao utilizar a noite(晚上使用感覺非常舒服)。」
D7 功能留存達到 93–94%
| 平台 | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9 | D10 | D11 | D12 | D13 | D14 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Android | 100% | 95% | 95% | 94% | 94% | 93% | 93% | 93% | 92% | 92% | 92% | 91% | 91% | 91% | 91% |
| iOS | 100% | 96% | 96% | 95% | 95% | 95% | 94% | 94% | 94% | 94% | 93% | 93% | 93% | 93% | 92% |
D7 功能留存 93–94%,D14 留存 91–92%。這個量級的留存罕見。表示開啟過的使用者幾乎不會回頭把它關掉。
下一步
我們會再補上其他頁面,讓 Dark Mode 覆蓋完整的 App。
看影片的畫面(Live View、Playback、Download)一直是疊在暗的影片上面,跟一般介面不太一樣,這部分我們也會持續調整。