web design uiMay 29, 20269 min read

Design Tokens: リアルなデザインシステムが一貫性を保つ方法

Design token とは何か、リアルなシステムが使う3層モデル(Shopify Polaris、IBM Carbon、GitHub Primer)、命名方法、ダークモードのテーマ設定、そしてトークンがオーバーキルになるタイミング。

By Boone
XLinkedIn
design tokens

Design Tokens: リアルなデザインシステムが一貫性を保つ方法

ヘックスコードは値だ。トークンは名前を持った意思決定だ。デザインシステムは値ではなく、意思決定で構成されている。

この違いこそが本質だ。#0EA5E9を14個の Figma コンポーネントにハードコードした状態でダークモードを求められたら、find-and-replace に一週間かかる。color-interactive-primaryと名付ければ、値を一箇所変えるだけですべてのサーフェスが更新される。魔法ではない。ただの名前付き意思決定だ。

Design token とは何か

Design token とは、デザインの意思決定を格納した名前付き変数だ。色、スペーシング値、フォントサイズ、ボーダー半径、シャドウ、デュレーションを保持できる。名前がコントラクトだ。名前の背後にある値は、それを使うものを壊すことなく変更できる。

古典的な非トークンアプローチは、デザイナーがプライマリボタンに#1D4ED8を選び、ボタンコンポーネントにハードコードし、そのヘックスをカード、バッジ、リンクにコピーするところから始まる。6ヶ月後、ブランドが更新される。出荷したすべてのコンポーネントに比例して膨らむメンテナンス問題が手元に残る。

トークンはそれを逆転させる。意思決定に名前を付け(color-action-default)、値を一度割り当てると、そのトークンを参照するすべてのものが同期を保つ。値は実装の詳細だ。名前がシステムだ。

トークンを機能させる3つの階層

生のトークンはただの変数だ。トークンシステムを実際に有用にするのは階層だ。研究に値するすべてのプロダクションシステムは3つの階層を使う。

階層別名格納内容
PrimitiveGlobal、Base生の値、意味なしcolor.blue.500 = #3B82F6
SemanticAlias、RolePrimitive にマッピングされた名前付きロールcolor.interactive.default = color.blue.500
ComponentSpecificコンポーネントスコープの意思決定button.background.default = color.interactive.default

Primitive はパレットだ。すべてのブルー、すべてのスペーシングステップ、すべての半径が、どこで使われるかについて意見を持たない名前付きの値としてここに存在する。コンポーネントで Primitive を直接消費しない。

Semantic トークンはロールを Primitive にマッピングする。トークンcolor-surface-defaultはライトモードではほぼ白、ダークモードではほぼ黒を指す場合があり、コンポーネントはどの生の値を受け取るかを知らない。知っているのはロールだけだ。

Component トークンは最も具体的だ。コンポーネントがデフォルトの Semantic から意図的に異なる意思決定を必要とするときに存在する。デンジャーボタンは背景をデフォルトのインタラクティブロールではなくクリティカルフィードバックロールに向ける。ほとんどのコンポーネントは独自のトークンを必要としない。Semantic トークンを直接消費する。

プリミティブスケール、セマンティックロール、コンポーネント決定という3つのスタックされたトークン階層を示すボクセルダイアグラム。
プリミティブスケール、セマンティックロール、コンポーネント決定という3つのスタックされたトークン階層を示すボクセルダイアグラム。

トークンがハードコードされた値に勝る理由

変更の速さは明白な主張だが、本当の主張ではない。本当の主張は精度だ。

デザイナーが生のヘックスコードだらけのファイルをハンドオフすると、開発者はどれが意図的でどれが偶然なのかわからない。#1A1A2Eは背景なのか、それとも誰かが間違ったレイヤーをアイドロップしたのか?トークンはその曖昧さを取り除く。Semantic トークンの名前は値と一緒に持ち運ばれるドキュメントだ。

トークンはまた、2026年においてデザインツールとコードの間のハンドオフコントラクトでもある。Figma の変数は CSS カスタムプロパティに直接マッピングされる。Figma ファイルで定義されたトークンは、一つの手動ステップなしにエクスポート、コミット、コードでの消費が可能だ。両者が同じトークン名を話すとき、デザインと実装のギャップは消える。

アクセシビリティ作業をするチームにとって、トークンはもう一層の安全性を加える。Semantic パレットを一箇所で監査し、どのテーマがアクティブであってもcolor-text-defaultcolor-surface-defaultに対して常に 4.5:1 のコントラストをクリアすることを保証できる。

リアルなデザインシステムのトークン構造

知っておく価値のある3つのシステムがある。Shopify Polaris、IBM Carbon、GitHub Primer だ。三層モデルの扱い方はそれぞれ異なり、その違いは示唆に富む。

Shopify Polaris はプリミティブをカラースケール(color-sky-100からcolor-sky-900)に保ち、--p-color-bg-fill-activeのような Semantic ロールにエイリアスする。Component トークンは少なく、ほとんどのコンポーネントは Semantic トークンを消費する。規則はロール次にステートで、コードで自然に読める。bg-fill-disabledが何のためかを追加のコンテキストなしに知ることができる。

カラートークンとその CSS カスタムプロパティ名と値が一覧されている Shopify Polaris トークンリファレンスページ。
カラートークンとその CSS カスタムプロパティ名と値が一覧されている Shopify Polaris トークンリファレンスページ。

polaris.shopify.com でライブを見る

IBM Carbon は Semantic 層を深く掘り下げる。カラーセットにはsupport-errorsupport-successのような明示的なフィードバックトークン、インタラクティブステートトークン、ネストされたサーフェスのレイヤートークン(ページ上のパネル上のコンポーネントはそれぞれ異なるサーフェス値が必要)が含まれる。より複雑だが、IBM はすべてのネストされたステートが重要なエンタープライズソフトウェアを出荷している。

インターフェースロールにマッピングされた Semantic カラートークンを示す IBM Carbon デザインシステムのカラーページ。
インターフェースロールにマッピングされた Semantic カラートークンを示す IBM Carbon デザインシステムのカラーページ。

carbondesignsystem.com でライブを見る

GitHub Primer は Primitive 層を「primitives」として、Semantic 層を「functional tokens」として公開し、primer.style でパブリックに文書化している。Primer のテーマ設定により、GitHub は単一のコンポーネントセットからライト、ダーク、ライトハイコントラスト、ダークディムドを出荷できる。すべてのテーマは同じトークン名への異なる値割り当てだ。

3つすべてに共通するパターンは一貫している。スケールとしての Primitive、ロール名としての Semantic トークン、Semantic 層での値スワップとしてのテーマ設定。コンポーネントはそのまま変わらない。


Brainy はデザイナーが使い捨てスクリーンではなくスケールするシステムを構築するのを支援する。クリエイターのために構築していることを/creatorsでご覧ください。


頭を抱えないトークン命名

トークンの命名はチームを分断する。汎用すぎると名前に情報がない。具体的すぎるとすべてのコンポーネントに新しいトークンを書く羽目になる。

機能する命名規則は4つの部分を命名する。カテゴリ、ロール、バリアント、ステートだ。毎回すべて4つを使うわけではないが、この構造がアドホックなカオスを防ぐ。

部分キャプチャする内容
Categoryデザインプロパティcolorspacingradiusshadowfont
RoleSemantic な目的surfacetextborderinteractivefeedback
Variantサブロールまたはモディファイアprimarysecondarydangersubtle
Stateインタラクティブな条件defaulthoveractivedisabledfocus

開発者が実際に消費する CSS カスタムプロパティとして書かれた実例:

  • color-surface-defaultはデフォルトのページ背景を設定する
  • color-text-subtleは低コントラストのセカンダリテキストだ
  • color-interactive-primary-hoverはプライマリアクションのホバーステートだ
  • spacing-component-mdはコンポーネントの中程度の内部パディングだ
  • radius-interactiveはクリッカブル要素のコーナー半径だ

最も多くの議論を救う2つのルール。名前に生の値を含めてはいけない。color-blue-500はロールについて何も伝えない。Semantic 層でコンポーネント名を付けてはいけない。Semantic 層のbutton-primary-colorは Semantic 層を完全にスキップしたことを意味する。

スケールするタイポグラフィシステムでも同じ規則が適用され、font-size-body-lgtext-18pxより常に優れている。

トークン名をカテゴリ、ロール、バリアント、ステートの4つの部分に分解したボクセルイラスト。
トークン名をカテゴリ、ロール、バリアント、ステートの4つの部分に分解したボクセルイラスト。

1セットのトークンでライトモードとダークモード

ダークモードはトークンシステムが最も目に見える形で報われる場所だ。トークンにロールで名前を付けていれば、ダークモードは再設計ではなく値のスワップだ。

1つのトークンセットからライト、ダーク、ハイコントラストのテーマを出荷している GitHub Primer デザインシステムサイト。
1つのトークンセットからライト、ダーク、ハイコントラストのテーマを出荷している GitHub Primer デザインシステムサイト。

primer.style でライブを見る

メカニズムは明快だ。Semantic トークンcolor-surface-defaultはライトモードではほぼ白、ダークモードではほぼ黒のプリミティブを指す。それを消費するコンポーネントは決して変わらない。Semantic 層での値マッピングをスワップすることでテーマを切り替える。

CSS カスタムプロパティはこれをメカニカルにする:

css
:root { --color-surface-default: #ffffff; --color-text-primary: #111827; } [data-theme="dark"] { --color-surface-default: #0f172a; --color-text-primary: #f8fafc; }

var(--color-surface-default)を参照するすべてのコンポーネントは、追加のコードゼロでテーマ属性に応答するようになる。Shopify Polaris、GitHub Primer、IBM Carbon はすべてプロダクションスケールでこのパターンを使用している。

失敗モードは Semantic トークンと Primitive トークンをコンポーネント内で混在させることだ。コンポーネントがcolor-interactive-primaryの代わりにcolor-blue-600を直接参照すると、そのコンポーネントはテーマ設定に応答しなくなる。不注意な Primitive 参照一つがモデル全体を壊す。コンポーネントコードでの直接 Primitive 消費にフラグを立てるリントルールは設定時間の価値がある。

色の選択がどのように伝わるかを理解することで概念的な基盤が得られ、トークンはすべてのテーマでそれを実行するための構造を提供する。

Design token がオーバーキルなとき

トークンは間接参照を加える。間接参照にはコストがある。そのコストを払う価値があるときについて正直になること。

状況トークン?理由
3プロダクト以上を提供するデザインシステムYes共有トークンはすぐに元を取る
単一プロダクト、5人以上のデザイナーYesチーム間のパレットのドリフトを防ぐ
単一プロダクト、1〜2人のデザイナー、活発なイテレーションMaybeSemantic 層のみ、Component トークンはスキップ
マーケティングサイト、コンポーネントライブラリなしNo1つのスタイルシートの方が変更が速い
3ヶ月未満のプロトタイプまたは MVPNoデザインが安定してから抽象化する
既存のシステムにダークモードを追加Yesこれはまさにトークンのためのユースケースだ

小チームはトークンなしの方が速く動ける。プロダクトマーケットフィットを追いかけている3人のスタートアップは3層の階層を必要としない。2週間ごとにビジュアルの方向性を変えるなら、単一の Figma スタイルライブラリで十分だ。

避けるべきアンチパターンは時期尚早な Semantic 命名だ。color-bluecolor-grayと命名されたトークンは意味なしに間接参照を加える。color-surfacecolor-textでロールで命名するか、実際のロールが何かを知るのに十分なコンポーネントができるまで Primitive にとどまること。

悪いトークン命名はトークンなしより悪い。Semantic 層のbutton-color-for-the-checkout-pageというトークンはメンテナンスの罠だ。命名の規律はオプションではない。それがトークンが機能する理由だ。

最小限の2トークン設定と過剰に設計された多層タワーを対比したボクセルイラスト。
最小限の2トークン設定と過剰に設計された多層タワーを対比したボクセルイラスト。

FAQ

Design token は Figma スタイルに取って代わるか?

いいえ、ただし拡張する。2023年にリリースされた Figma 変数は Figma 内部で最も近いネイティブの同等物であり、両側で命名規則を共有すればコードトークンにマッピングされる。Figma スタイルはタイポグラフィとカラーフィルを処理し、変数はステートとコンポーネントレベルの決定を含む完全なトークン階層を処理する。

デザインシステムなしでトークンは機能するか?

トークンはデザインシステム内で最も価値があるが、単一のプロダクトでも CSS カスタムプロパティレベルでの Semantic 命名から恩恵を受ける。ヘックス値のハードコードをやめるために正式なシステムは必要ない。

トークン管理にはどのツールを使うべきか?

小チームには、Figma 変数と JSON エクスポートで十分だ。大規模チームには、Style Dictionary(Amazon によるオープンソース)が標準のビルドツールだ。トークン JSON 構造を取り込み、CSS カスタムプロパティ、iOS Swift 定数、Android XML を出力する。Tokens Studio for Figma は Figma と Style Dictionary の間の人気のプラグインブリッジだ。

Component トークンはどの程度細かくすべきか?

必要な程度だけ。ほとんどのコンポーネントは Semantic トークンを直接消費できる。コンポーネント固有のトークンは、破壊的アクションボタンや異常なサーフェスを持つバナーのように、コンポーネントが意図的に Semantic 層から逸脱する場合に意味を持つ。迷ったときは Semantic を消費し、例外を書いていると気づいたときだけ Component トークンを作成すること。

トークンはスペーシングやタイポグラフィも処理できるか、それとも色だけか?

トークンは離散値を持つあらゆるものに機能する。色、スペーシング、タイポグラフィ、ボーダー半径、ボックスシャドウ、モーションデュレーション、モーションイージング、z-index。IBM Carbon や Atlassian Design System のような最も成熟したシステムには、これらすべてのトークンがある。色とスペーシングから始め、システムが成熟するにつれて他のものを追加すること。

ハードコードをやめる

実践的なパスは複雑ではない:

  • Primitive をスケールとして命名する
  • それらの Primitive を Semantic ロールにマッピングする
  • すべてのコンポーネントが Primitive ではなく Semantic トークンを消費するようにする
  • 1つのソース(Figma 変数、JSON ファイル、またはデザインシステムパッケージ)からトークン値をエクスポートし、ビルドツールに CSS、iOS、Android への配布を任せる

始めるのに3ヶ月のマイグレーションは必要ない。1つのコンポーネントを選び、その意思決定に名前を付け、値を1箇所変えてすべてが更新されるのを見たときの感覚の違いを感じること。その経験が論拠だ。

デザインシステムのその他の記事については、Brainy が/paperでカバーしている内容を見てみよう。

Brainy helps designers build systems that scale, not one-off screens. See what we are building for creators.

Get Started

More from Brainy Papers

Keep reading