mcpField
T
tailwind-token-consolidation

tailwind-token-consolidation

github.com/millioncoデザイン・UI3448 回インストール17 週間前に更新
リポジトリ

tailwind-token-consolidation について

Tailwind v4 の `globals.css` で、見た目を保ちながらデザイントークンを整理するワークフロー技能です。使用状況の分析、安全な削除と統合、スクリプトによる名前変更、ビルド検証の手順を示します。

主な機能

  1. 01プロジェクト内のトークン使用状況を把握
  2. 02依存関係をたどって使用中トークンを特定
  3. 03未使用トークンを安全に削除
  4. 04値の近いトークンを統合
  5. 05スクリプトで名前変更を適用
  6. 06ビルドと表示値を検証

活用シーン

  1. 01Tailwind v4 のトークンセットを監査
  2. 02重複するデザイントークンを削減
  3. 03スコープ別とダークモードのスタイルを維持

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/millionco/skills --skill tailwind-token-consolidation

インストール後、Claude Code で/tailwind-token-consolidationを入力して読み込まれたか確認します。

詳細

Tailwind トークンの統合

見た目を維持しながら、Tailwind v4 の globals.css にあるデザイントークンの数を減らします。

すべての統合タスクで、以下の手順を必ず順番どおりに実行してください。

  1. まず監査し、最初から編集しないでください。 globals.css を構造化ブロック(@theme inline、:root、.dark、その他すべてのスコープ付きブロック)に解析します。トークン数を数えます。すべての .ts/.tsx/.css/.mdx ファイル(globals.css を除く)をスキャンし、クラス名と var(--...) 参照の使用状況マップを作成します。
  2. 推移的に LIVE セットを計算します。 トークンは、(a)そのサフィックスが Tailwind クラスとしてどこかに現れる、(b)どこかで var(--name) として参照される、または(c)別の live トークンの値の中で参照される場合に live です。固定点に達するまで反復します。
  3. globals.css 内のユーティリティクラスもスキャンします。 .X { ... } ブロック(:root/.dark/@theme inline の外)にある var(--...) は、すべてハード依存関係です。これらのクラスが必要とするトークンは必ず残してください。
  4. 決定的な名前変更マップをデータとして作成し(old_suffix -> new_suffix または DELETE)、単一のスクリプトで globals.css とコードの両方に適用します。コードベース全体のクラス名を手作業で編集しないでください。
  5. 各パスの後に検証します。 pnpm typecheck、pnpm lint、pnpm format、pnpm build を実行してください。完了を宣言する前に、すべて成功する必要があります。

どの手順も省略しないでください。手順を省略した場合、そのタスクは失敗です。

2 つの削減方法(この順番で適用)

方法削減対象リスク
1. 未使用トークンの削除コードでの使用も、globals 内の依存もないトークンなし — 安全
2. 値が類似したトークンの統合ライトモードとダークモードの両方で値が約 5% 以内に収まる場合、--button → --card に名前を変更小 — 本当に類似した値のみ選ぶ

トークンを Tailwind の任意値(px-[17px]、text-[16px]/[1.6875rem]、shadow-[#000_0px_1px])にインライン化しないでください。インライン化しても、名前付きトークンの煩雑さが任意値の煩雑さに置き換わるだけで、ノイズの量は変わらず、場所が変わるだけです。名前付きトークンには意図が込められていますが、任意値はそれを損ないます。この 2 つの方法だけで現実的に削減できるのは 50~60% であり、70% ではありません。ユーザーがそれ以上の削減を求めた場合は、より多くのトークンを減らすのではなく、className 文字列内のノイズを同じだけ増やすことになると説明し、要求を再考してもらってください。

遭遇する 8 つのバグ(事前に対策してください)

  1. 値の優先順位に関するバグ。 N 個のトークンを 1 つの正規名に統合すると、解析順によって先勝ちになるため、結果が予測できません。誤った色になることもよくあります(例:--danger が --diagnostics-table-error-border の値を持つようになる。これは鮮やかな赤ではなく、淡い枠線の色合いです)。対策: 新しいトークンに対して、どのソーストークンの値を優先するかを指定する CANONICAL_SOURCE の明示的なオーバーライド辞書を追加します。

  2. スコープ付きオーバーライドに関するバグ。 .dashboard-page { --text-inline: 14px; } が機能するのは、--text-inline が var() で参照されるカスタムプロパティだからです。いずれかのスコープ付きブロック(.dashboard-page、.dark .dashboard-page など)で上書きされているトークンは、必ずトークンとして残してください。削除すると、スコープ付きオーバーライドが気づかれないまま壊れます。

  3. globals 内の使用箇所に関するバグ。 globals.css 内のユーティリティクラス(例:.dropdown-menu-highlight { padding: var(--spacing-dropdown-menu-padding); })は、どの .tsx ファイルにも現れないトークンを読み取ります。これらを @theme から削除すると、実行時に CSS 変数が未定義になります。対策: スキャン前に CSS テキストから @theme inline/:root/.dark などのブロックを取り除き、残りからすべての var(--X) 参照を収集します。これらのトークンは必ず残してください。

  4. カテゴリの混同に関するバグ。 1 つのサフィックスが複数のカテゴリに現れることがあります。たとえば、organization-section-surface は色(white)であると同時に、シャドウのエイリアスの接頭辞(--shadow-organization-section-surface)でもあります。マップに色用の 'organization-section-surface': 'card' とシャドウ用の 'organization-section-surface': 'surface-soft' の両方があると、後者がグローバルマップ内の裸のトークンの名前変更を上書きします。対策: 裸の --X トークンの名前を変更するのは色カテゴリだけにします。SHADOW/SPACING/TEXT/RADIUS/FONT/TRACKING では、裸の名前は変更せず、--<theme-prefix>-X のエイリアスのみを変更します。

  5. アイコンカラーを過度に統合するバグ。 すべての「グレーのアイコン」(#696969、#898989、#b3b3b3、#c1c1c1、#dddddd)を単一の --icon トークンに統合すると、もともと明るかったアイコンが目に見えて暗くなります。また、暗い背景(両モードで暗いままのドロップダウンメニューなど)では、意図したコントラストが反転します。修正方法: アイコンの色調を2種類(--icon(約#696969のミディアムグレー)と--icon-soft(約#b3b3b3のライトグレー))維持します。もともと明るかったアイコンは--icon-softに割り当てます。

  6. 透明度が条件によって変わるサーフェスのバグ。 一部のトークンは、片方のモードではtransparent、もう片方のモードでは具体的な色になります(例:ライトモードでは--repository-card-panel: #ffffff、ダークモードではtransparent。ダークモードでは意図的に背景が透けて見えるようになっています)。これを--cardに統合すると、ダークモードでパネルが不透明になり、レイヤー表現が目に見えて変わります。修正方法: あるモードではトークンの値がtransparent、もう片方では具体的な色の場合、常に不透明なトークンと統合しないでください。別々のトークンとして維持するか、使用するclassNameに条件分岐のロジックを直接記述します。

  7. bg-Xの色と画像の衝突によるバグ。 Tailwind v4はbg-Xを--color-X(背景色)と--background-image-X(背景画像)の両方に照合します。--background-image-Xしか存在しない場合、bg-Xはグラデーションを正しく描画します。しかし、別のトークン(例:--install-button-text)を--install-buttonに名前変更すると、--color-install-buttonのエイリアスが作成されます。その結果、bg-install-buttonがグラデーションの上にbackground-color: whiteを設定し、ボタンが空白または見えなくなることがあります。修正方法: 色の接尾辞をXに変更する前に、--background-image-Xとbg-Xクラスの使用箇所をgrepで検索します。どちらかが存在する場合は、別の名前を選びます(例:--install-buttonに名前変更せず、--install-button-textを維持します)。

  8. 常に暗いサーフェスのバグ。 ドロップダウンメニュー、ツールチップ、常に暗いままのポップオーバーなどのトークンは、サーフェスがテーマに関係なく暗いままのため、テキストやアイコンの色がライトモードとダークモードの両方で明るくなっています。--dropdown-menu-textを--foregroundに統合すると、ライトモードでドロップダウンのテキストが暗くなり(暗いサーフェスに暗いテキストが重なって見えなくなり)ます。修正方法: トークンを統合する前に、ライトモードとダークモードの値を比較します。どちらの値もL=0.5の境界線の同じ側(どちらも明るい、またはどちらも暗い)にある場合、そのトークンは常に明るい、または常に暗いサーフェス上にあり、--foregroundや--iconのようにモードによって切り替わるトークンとは統合できません。独立したトークンとして維持します。

3段階のブロック変換

:rootまたは.darkブロックを出力する際は、以下の順序でエントリーを記述します。

# Pass 1: canonical (non-renamed) entries — these set the source of truth.
for name, value in original_decls.items():
    target = TOKEN_RENAME.get(name)
    if target is None or target == name:
        out[name] = fix_var_refs(value)

# Pass 2: CANONICAL_SOURCE overrides — explicit pick for collapsed groups.
for new_token, source_token in CANONICAL_SOURCE.items():
    if source_token in original_decls:
        out[new_token] = fix_var_refs(original_decls[source_token])

# Pass 3: other renamed entries — only if the target isn't already set.
for name, value in original_decls.items():
    target = TOKEN_RENAME.get(name)
    if target and target != name and target not in out:
        out[target] = fix_var_refs(value)

これにより、(a)正規トークンの元の値が常に名前変更後の値より優先されること、(b)--dangerのような新しいトークンにどの値を割り当てるかを明示的に制御できること、(c)出力に重複したエントリーが現れないことが保証されます。

適用・検証ループ

名前変更マップを変更するたびに、必ずこのループを実行します。

git checkout -- apps/web   # always start from a clean tree
python3 /tmp/transform.py  # apply the rename + inline map
pnpm typecheck && pnpm lint && pnpm format && pnpm --filter web build

チェックに失敗した場合は、生成された出力ではなくマップを修正してから、再実行します。生成後のglobals.cssを手作業で編集するのは危険です。次の変換実行時に修正が上書きされます。

合理化の判断表

こう考えてしまうしてはいけないこと
「このトークンは削除しても大丈夫。使っている人はいない」— globals.css 内のクラスを検索せずに@theme/:root/.dark ブロックを取り除き、まず残りの部分で var(--X) を検索してください
「この2つのグレーはほとんど同じ」— ライトモードとダークモードの両方の値を確認せずに両方のモードを比較してください。ライトモードでは近い値でも、ダークモードでは大きく異なることがあります
「削減効果を高めるために、1か所だけで使うトークンを任意の値にインライン化しよう」それはノイズを別の場所に移しているだけです。名前付きトークンを維持してください。インライン化は集約に反します
「ユーザーが70%を指定したから、インライン化してでも達成しよう」異議を唱えてください。任意の値で70%にするより、名前付きトークンで50~60%にするほうが適切です。正直な数値を報告してください
「スクリプトの実行後に、壊れたクラスを手作業で直そう」次にスクリプトを実行すると、変更は元に戻ります。成果物ではなく、スクリプトを修正してください
「先に書かれた値を優先すれば問題ない。解析順は決定的だから」:root の順序が変更されるまでは問題ありません。CANONICAL_SOURCE で明示的に上書きしてください
「この名前への変更で問題ない。衝突はない」— すでに --background-image-<name> があるのに変更先の名前を決める前に、--background-image-<target> と bg-<target> の使用箇所を grep で検索してください

完了を宣言する前に

必ず以下を実施してください。

  1. pnpm typecheck を実行してください — 終了コードが0であること。
  2. pnpm lint を実行してください — エラーも警告も0件であること。
  3. pnpm format を実行してください — 完了していること。
  4. pnpm --filter web build を実行してください — 終了コードが0であること。
  5. rg "^\s*--[a-z][a-zA-Z0-9-]*\s*:" apps/web/app/globals.css -o | sort -u | wc -l で最終トークン数を数えてください。変更前後の数と削減率を報告してください。
  6. 生成された :root ブロックを最初から最後まで読み、正規値が想定どおりであることを確認して、少なくとも上位3つの表示領域(カード、ページ背景、ドロップダウン)に意図した色が描画されていることを確認してください。

ビルドが成功していても、表示が壊れていればタスクは失敗です。削減数を数えても、検証していなければタスクは失敗です。

コメント