建立 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 各自維護一套命名。三個平台分別又混合了多種不同的命名邏輯,有些名字描述外觀,例如 gray3offWhite。有些名字描述元件,例如 primaryButton。完全沒有規則決定什麼情況該用哪一種。

色碼iOSAndroidFigma
#FCC35D
primaryYellowyellow_accentYellow/Base
#FFFFFF
mainBgbackground_mainBackground/Primary
#E9683F
alertRederror_colorRed/500
#00BA86
successGreengreen_500Green/600
#FD9728
warningOrangeorange_500Orange/500
整理之前,同一個色碼會有三個不同的名字

色彩並不是會隨意修改的元素,現況雖難以維護但結構還算單純所以堪用,不過一旦要加第二個主題時,沒有系統的管理這些命名問題就會變得很明顯:一個元件要改顏色的時候,要怎麼快速找到對應的名稱、一次改動不同主題的色碼?

真正要解的不是「Dark Mode 要長什麼樣」,而是「主題本身要怎麼被管理」。

核心頁優先,細節頁延後

兩週時程不可能把所有頁面都做進來。團隊把範圍收斂在使用者最常進入的頁面(設定頁、主要頁),把長尾細節頁面延後。

設計規劃

Token 分層:基礎層給設計師管理源頭、語意層讓產品使用

Token 分成兩層,但設計師跟工程師實際使用的是同一層。

  1. Semantic:設計跟程式端元件實際在使用的 Token。
  2. Primitive:是語意層顏色的源頭色盤,元件顏色不直接使用。設計師只在「創建色盤」的時候才會動到它,其餘時間基本上不會動用到這個色盤。

切分成兩層的好處是,任何顏色變動都只發生在同一個地方。換主題的時候,改的是 Semantic 對應到哪個 Primitive;調品牌色或做無障礙微調的時候,改的是 Primitive 本身的值,所有引用它的 Semantic 都會跟著更新。不管哪一種,Figma 組件跟 code 都不用動名稱,只需要調整色碼。

  • primary

    LightYellow.600
    #FCC35D
    DarkYellow.600
    #FCC35D
  • surface

    LightNeutral.50
    #FFFFFF
    DarkNeutral.900
    #212121
  • error

    LightRed.500
    #E9683F
    DarkRed.400
    #F77C56
  • success

    LightGreen.600
    #00BA86
    DarkGreen.500
    #00C28C
  • highlight

    LightOrange.500
    #FD9728
    DarkOrange.400
    #EB8A1B
每個顏色的 Light 跟 Dark 色碼對照

不分模式的命名,只改值不改名

Semantic 名字裡不會出現 light dark 字樣。名字描述的是「在系統中的角色」,不是「在哪個模式下長什麼樣」。Spec 把這件事寫成兩條硬性規則。

  1. Light 跟 Dark 必須使用同一個 token 名字。
  2. 切換 mode 改的是值,不是名字。

code 引用的那一行一直一樣,在 Light 時解析到 Light 的值,在 Dark 時解析到 Dark 的值,使用端永遠只寫一行。以後加第三、第四個 theme(high-contrast、brand theme、accessibility)的時候,不用改名,也不用整個 codebase 找替換。

用 camelCase 當命名規則

Token name 採用 camelCase。當時討論過 kebab-case 跟 snake_case,最後選 camelCase 有兩個理由。

  1. 平台兼容性。 iOS(Swift、Objective-C)和 Android(Kotlin、XML)都能讀通同一份名字,不需要做平台轉換。
  2. 穩定性。 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
切 Light 或 Dark 看每個顏色一起被重新平衡

結果

後測 Survey 拿到 4.5 / 5

4.5 / 588.76% 給 4 或 5 星

總回覆 685 份

5 星

501 (73.14%)

4 星

107 (15.62%)

3 星

41 (5.99%)

2 星

8 (1.17%)

1 星

28 (4.09%)

後測 Survey · 685 份回覆

後測 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%

平台D0D1D2D3D4D5D6D7D8D9D10D11D12D13D14
Android100%95%95%94%94%93%93%93%92%92%92%91%91%91%91%
iOS100%96%96%95%95%95%94%94%94%94%93%93%93%93%92%
Auto System Theme 功能留存(D0 → D14)

D7 功能留存 93–94%,D14 留存 91–92%。這個量級的留存罕見。表示開啟過的使用者幾乎不會回頭把它關掉。

下一步

我們會再補上其他頁面,讓 Dark Mode 覆蓋完整的 App。

看影片的畫面(Live View、Playback、Download)一直是疊在暗的影片上面,跟一般介面不太一樣,這部分我們也會持續調整。

© 2026 FANG LO

版權所有