這次研究 Design Tokens 的起點,是因為主管提出了一個很實際的需求:希望 UI/UX 定義的樣式,能和前端實際使用的顏色、字體、間距與圓角保持一致。
聽起來好像只是把 Figma 裡的值匯出,再轉成 CSS variables 就結束了。但真的開始研究後,我才發現困難的不是「怎麼轉」,而是設計改動離開 Figma 之後,怎麼安全地進到前端。
如果中間沒有一套交付流程,很快就會遇到幾個問題:Token reference 有沒有斷?型別和命名是否一致?這次修改會不會影響既有畫面?前端現在使用的是哪一版?出問題時又要怎麼回滾?
這篇文章記錄我最後整理出的做法:用 Tokens Studio 把設計決策轉成接近 DTCG 規範的 Token JSON,再透過 GitLab CI 驗證與產生 CSS,由 CI bot 建立 Merge Request。人工 review、merge 之後,由前端工程師建立 Git tag;前端專案再透過 npm Git dependency 與 lockfile 主動升版。
案例來自一組實際運作的雙 repository 架構,但本文只保留去識別化後的職責、產物與版本流向。專案名稱、Git URL 與版本號都是示意,也不會貼出內部原始碼。
一開始拿到的 JSON,前端還不能直接用
最初 UI/UX 提供給我的 JSON,比較像 Figma Variables 的 raw data,裡面包含 id、variableIds、valuesByMode、resolvedValuesByMode 等欄位。
這些資料對還原 Figma 內部狀態有幫助,但前端真正需要的不是 variable ID,而是穩定的 Token 名稱、型別、值、語意與 reference。也就是說,我希望最後拿到的資料更接近 Design Tokens Format Module 的結構:
{
"color": {
"text": {
"default": {
"$type": "color",
"$value": "{color.grey.900}",
"$description": "預設文字顏色"
}
}
}
}
這裡需要補充一個容易混淆的地方:Design Tokens Format Module 2025.10 已經是穩定的 Final Community Group Report,但不是 W3C Standard。它定義了工具之間交換 Design Tokens 的格式;其中 $value 是必要欄位,$type 可以寫在 Token 本身,也可以由上層 group 繼承,而 $description 是選填。
所以我真正要解的問題,不是把一份 JSON 換成另一份 JSON,而是:
怎麼把 Figma 裡的設計決策,整理成設計端和前端都能理解,而且可以被版本控制的資料?
為什麼會研究 Tokens Studio?
沿著這個問題找下去,我開始研究 Tokens Studio for Figma。
Tokens Studio 是一套在 Figma 裡建立與管理 Design Tokens 的工具。UI/UX 可以用介面維護顏色、字體、間距、圓角等設計決策,也可以用 Alias 把原始值和語意用途分開。例如 text.default 不直接寫色碼,而是引用 color.grey.900。
它在這套流程裡主要處理四件事:
- Token Set:把不同類型或用途的 Token 分組管理。
- Alias / Reference:讓語意 Token 引用基礎 Token,避免到處複製相同的值。
- Theme:組合 Light、Dark 或不同品牌需要的 Token Sets。
- Remote Storage:把 Token 同步到 Git repository,讓變更進入版本控制。
不過,把現有 Figma Variables 匯入 Tokens Studio 之後,也不代表資料會自動變成可以交付的 Token。Type、Naming、Alias 和 Description 還是需要和 UI/UX 一起整理。Tokens Studio 解決的是管理和交換格式,並不會代替團隊做設計語意的決定。

Tokens Studio 預設可以把 Token 存在目前的 Figma 文件,也能新增 Remote Storage。這讓 Token 不再只存在某一份設計稿裡,而是可以和工程端共用同一份 source of truth。
把 Tokens Studio 接到 GitLab
在 Settings 裡新增 Sync Provider 時,可以看到 GitHub、GitLab、Azure DevOps、Bitbucket 等選項。

選擇 GitLab 之後,需要設定名稱、Personal Access Token、repository、branch、Token 儲存路徑;如果是自架 GitLab,也可以填 Enterprise Base URL。

這裡的 branch 由工程端事先設定成固定的 sync branch。UI/UX 平常只需要在 Figma 裡確認 Token,然後按 Push,不需要自己切 branch、開 MR 或決定版本號。
也就是說,設計師的操作流程其實很短:
調整 Token → 確認 Figma 畫面 → Push
branch、CI、MR、merge 與 tag 是後面的工程交付流程,不應該變成設計師每天需要處理的 Git 工作。
設計師 Push 之後會發生什麼?

完整流程可以整理成:
Tokens Studio Push
→ 固定的 sync branch
→ CI 驗證 Token
→ Style Dictionary 產生 CSS 與 dist
→ CI bot commit dist
→ CI 建立或更新 MR
→ MR pipeline 與人工 review
→ merge protected default branch
→ 前端工程師建立 Git tag
→ 前端專案透過 MR 升版
這裡有幾個責任邊界,是我研究過程中花最多時間釐清的地方。
CI 先驗證 Token,再產生前端產物
固定的 sync branch 收到 Token JSON 後,就會觸發 branch pipeline。CI 先檢查:
- JSON 格式是否正確。
- Alias / Reference 指向的 Token 是否存在。
- Token type 是否符合預期。
- Naming 是否符合團隊規則。
驗證失敗時,pipeline 直接停止,再把錯誤交回 UI/UX 修正。設計師修正後重新 Push 就好,不需要介入後面的 Git 操作。
驗證通過後,CI 再執行 Style Dictionary,把 Token 轉成前端真正會使用的 CSS variables 與 theme assets。
:root {
--color-text-default: #1f2937;
--spacing-md: 1rem;
--radius-card: 0.75rem;
}
在這個案例裡,前端會直接把 Token repository 當成 Git dependency 安裝,所以 dist/ 需要和 source 一起進版控。CI bot 會把重新產生的 dist/ commit 回同一個 sync branch,讓 MR 同時看得到 Token source 與建置產物的差異。
MR 建立
我的做法是把它設計成 CI pipeline 裡的一個 job:前面的 validation、Style Dictionary build 與 dist commit 都成功後,這個 job 使用專用的 bot 身分呼叫 GitLab Merge Requests API。
它會先確認目前的 sync branch 是否已經有開啟中的 MR:
- 沒有,就建立一張從 sync branch 合併到 protected default branch 的 MR。
- 已經有,就沿用同一張 MR,讓新的 Push 與 dist commit 繼續更新內容。
所以更精確的說法是:MR 由 CI job 透過 GitLab API 建立或更新,人負責 review 與 merge。
MR pipeline 會再從乾淨環境重新 build,確認 committed dist/ 確實能由 Token source 重現。接著由 UI/UX 確認設計語意與視覺結果,前端工程師則 review 命名、相容性和產品影響。
Merge 後,用 Git tag 建立版本
MR 通過並 merge 到 protected default branch 後,tag 不會由 UI/UX 建立,我也不會讓 CI 每次 merge 都自動決定版本號。
這一步由負責 Token repository 的前端工程師執行。原因很簡單:patch、minor 或 major 不只是流水號,而是對消費端的相容性承諾。負責 release 的人要先判斷這次變更是否破壞既有 Token,確認版本後,再建立 annotated tag,例如:
git tag -a v0.3.0 -m "Release design tokens v0.3.0"
git push origin v0.3.0
Default branch 代表目前最新的整合狀態,Git tag 才是前端可以鎖定、回溯與回滾的 release boundary。
前端怎麼使用這一版 Token?
在沒有 Package Registry 的環境裡,前端可以先用 npm Git dependency 指向特定 tag:
{
"dependencies": {
"@example/design-tokens": "git+https://git.example.com/design-system/tokens.git#v0.3.0"
}
}
要升版時,前端另外開一張 MR,更新 package.json 裡的 tag,執行 npm install 更新 package-lock.json,再跑 build、test 與必要的 visual check。
這裡我不讓產品專案自動追 default branch,因為 Token 更新即使沒有語法錯誤,也可能造成大量視覺變化。由前端主動升版,會多一個 commit 和 MR,但也留下了明確的 review 與 rollback 點。
為什麼不用 Package Registry?
比較標準的做法,是把 Design Tokens 包成 npm package,再由 CI publish 到 Package Registry。但實務上不一定每個團隊都有可用的 registry、runner 或維運權限。
我遇到的是舊版自架 GitLab,沒有可用的 npm Package Registry。與其先為一個理想架構擴充基礎設施,我選擇先讓 Git repository 自己成為 package source:
- Token source 與
dist/一起接受 review。 - Git tag 定義正式版本。
- 消費端沿用既有 Git 權限安裝。
- lockfile 保存實際解析到的 commit。
這不是要取代 Registry,而是一條可以演進的路徑:vendored copy → Git dependency → Registry package。未來基礎設施成熟後,只要更換 dependency source,不需要重做整套 Token 架構。
最後整理
回頭看這次研究,我最後解的其實不是「怎麼把 Figma 轉成 CSS」,而是怎麼替設計變更補上一條工程交付流程。
Tokens Studio 負責把設計決策結構化;DTCG JSON 提供工具之間可以交換的格式;CI 與 Style Dictionary 負責驗證和產生前端產物;MR 留下人工 review;Git tag 定義可被消費的版本;前端的 dependency MR 與 lockfile 則負責可控升版和回滾。
最後,UI/UX 的日常工作仍然只有在 Figma 裡整理 Token、確認畫面並 Push。後面的 branch、CI、MR、merge、tag 和前端升版,由工程流程接手。
我覺得這才是 Design Tokens 真正有價值的地方:是設計與前端開始共用同一套可以被理解、被驗證,也能安全回退的設計決策。
