マルチネームスペーストークン戦略
問題
タイトトークン戦略では、プロジェクト固有のセマンティックトークンを定義します。例えば、ブログ中心のウェブサイトでは、記事コンテンツに最適化されたスペーシングとフォントサイズのトークンを myweb- というネームスペースで定義します:
@theme {
/* myweb namespace — article-focused tokens */
--spacing-myweb-content-gap: 32px;
--spacing-myweb-section-gap: 48px;
--spacing-myweb-reading-padding: 24px;
--font-size-myweb-body: 1.125rem;
--font-size-myweb-heading: 2rem;
}
サイトが成長するにつれて、新しい機能が追加されていきます。ログイン画面、管理ダッシュボード、設定パネル — これらの UI は記事コンテンツとは根本的に異なるデザインルールを必要とします。管理画面はよりタイトなスペーシング、小さなフォントサイズ、密度の高いレイアウトを求めます。
1つのネームスペースにすべてを押し込むとどうなるか:
@theme {
/* myweb namespace — growing out of control */
--spacing-myweb-content-gap: 32px;
--spacing-myweb-content-gap-dense: 16px; /* admin用に追加 */
--spacing-myweb-section-gap: 48px;
--spacing-myweb-section-gap-compact: 24px; /* admin用に追加 */
--spacing-myweb-reading-padding: 24px;
--spacing-myweb-panel-padding: 12px; /* admin用に追加 */
--font-size-myweb-body: 1.125rem;
--font-size-myweb-body-dense: 0.875rem; /* admin用に追加 */
--font-size-myweb-heading: 2rem;
--font-size-myweb-heading-compact: 1.25rem; /* admin用に追加 */
}
トークンが増えるたびに -dense、-compact、-small といった接尾辞が付きます。トークンセットは肥大化し、どのトークンがどのコンテキストに属するのか分からなくなります。タイトトークン戦略の本来の目的 — 「少ない選択肢で明確なルールを作る」— が損なわれます。
解決方法
デザインコンテキストごとに別のネームスペースを使います:
myweb-— 記事・コンテンツのデザインルールmyadmin-— 管理画面・ダッシュボードのデザインルール
@theme {
/* ── myweb namespace: article/content ── */
--spacing-myweb-content-gap: 32px;
--spacing-myweb-section-gap: 48px;
--spacing-myweb-reading-padding: 24px;
--font-size-myweb-body: 1.125rem;
--font-size-myweb-heading: 2rem;
/* ── myadmin namespace: admin/dashboard ── */
--spacing-myadmin-cell-gap: 8px;
--spacing-myadmin-section-gap: 16px;
--spacing-myadmin-panel-padding: 12px;
--font-size-myadmin-body: 0.875rem;
--font-size-myadmin-heading: 1.25rem;
}
各ネームスペースは独立したデザインコンテキストです。myweb- のトークンは読みやすさを最適化し、myadmin- のトークンは情報密度を最適化します。-dense や -compact のような接尾辞は不要です — トークン名のネームスペースプレフィックスが、そのトークンの適用先を明確にします。
ネームスペース分割の判断基準
ネームスペースを分ける必要があるのは、2つのコンテキストが異なるデザイン原則を持つ場合です:
| シグナル | 例 |
|---|---|
| スペーシングの基準が異なる | 記事は余白が広い / 管理画面はタイト |
| フォントサイズの基準が異なる | 記事は読みやすさ重視 / ダッシュボードは密度重視 |
| 同じ目的のトークンに異なる値が必要 | 「ボディテキスト」が記事では 18px、管理画面では 14px |
-dense/-compact 接尾辞が増え始めた | 1つのネームスペースに収まらないサイン |
逆に、以下の場合は分割不要です:
| シグナル | 理由 |
|---|---|
| レスポンシブで値が変わるだけ | メディアクエリやコンテナクエリで対応 |
| テーマ(ライト/ダーク)の切り替え | カラースキームで対応 |
| 微妙なバリエーション | 既存トークンのスケール(sm/md/lg)で対応 |
コード例
単一ネームスペース(肥大化した状態)
@theme {
/* すべてが myweb- に押し込まれている */
--spacing-myweb-content-gap: 32px;
--spacing-myweb-content-gap-dense: 16px;
--spacing-myweb-section-gap: 48px;
--spacing-myweb-section-gap-compact: 24px;
--spacing-myweb-reading-padding: 24px;
--spacing-myweb-panel-padding: 12px;
--font-size-myweb-body: 1.125rem;
--font-size-myweb-body-dense: 0.875rem;
--font-size-myweb-heading: 2rem;
--font-size-myweb-heading-compact: 1.25rem;
}
トークンの数が多く、どれが記事用でどれが管理画面用かが名前から推測しにくい。
マルチネームスペース(分割後)
@theme {
/* ── myweb: 記事コンテンツ ── */
--spacing-myweb-content-gap: 32px;
--spacing-myweb-section-gap: 48px;
--spacing-myweb-reading-padding: 24px;
--font-size-myweb-body: 1.125rem;
--font-size-myweb-heading: 2rem;
/* ── myadmin: 管理ダッシュボード ── */
--spacing-myadmin-cell-gap: 8px;
--spacing-myadmin-section-gap: 16px;
--spacing-myadmin-panel-padding: 12px;
--font-size-myadmin-body: 0.875rem;
--font-size-myadmin-heading: 1.25rem;
}
各ネームスペースのトークン数は少なく、適用先がプレフィックスから明確です。
コンポーネントでの使い方
<!-- 記事ページ — myweb トークンを使用 -->
<article class="px-myweb-reading-padding">
<h1 class="text-myweb-heading pb-myweb-content-gap">Article Title</h1>
<p class="text-myweb-body pb-myweb-section-gap">
Long-form content with generous reading spacing...
</p>
</article>
<!-- 管理ダッシュボード — myadmin トークンを使用 -->
<div class="p-myadmin-panel-padding">
<h2 class="text-myadmin-heading pb-myadmin-cell-gap">Dashboard</h2>
<table class="text-myadmin-body">
<tr><td class="p-myadmin-cell-gap">Row 1</td></tr>
<tr><td class="p-myadmin-cell-gap">Row 2</td></tr>
</table>
</div>
Tailwind クラスのネームスペースプレフィックスが、各コンポーネントのデザインコンテキストを即座に伝えます。
デモ:単一ネームスペース vs マルチネームスペース
左側は単一ネームスペースにすべてを押し込んだ状態です。-dense、-compact といった接尾辞でトークンが増殖し、どのトークンがどのコンテキスト向けか判別しにくくなっています。右側はネームスペースで分割した状態です。各ネームスペースのトークン数は半分になり、プレフィックスが適用先を明示しています。
デモ:記事コンテンツ vs 管理ダッシュボード
以下のデモは、同じウェブサイト内の2つの異なるデザインコンテキストを示しています。左の記事 UI は広いスペーシングと大きなフォントを使い、右の管理 UI はタイトなスペーシングと小さなフォントを使っています。
記事コンテキストでは myweb-content-gap(32px)の広い垂直ギャップと myweb-body(1.125rem)の大きなフォントで読みやすさを重視しています。管理コンテキストでは myadmin-cell-gap(8px)のタイトなスペーシングと myadmin-body(0.875rem)の小さなフォントで情報密度を最大化しています。
デモ:3つのネームスペースを持つ大規模サイト
サイトの規模が大きくなると、3つ以上のネームスペースが必要になることもあります。以下は記事、管理画面、マーケティングページの3コンテキストの例です。
各ネームスペースが独立したデザイン原則を持っています。myweb- は読みやすさ、myadmin- は情報密度、mymarketing- はインパクトに最適化されています。同じプロパティ名(body、section-gap)がネームスペースごとに異なる値を持つことで、コンテキストに応じた最適なデザインが実現されます。
クイックリファレンス
| シナリオ | アプローチ |
|---|---|
| サイト全体が同じデザインルール | 単一ネームスペースで十分 |
| 記事コンテンツ + 管理画面 | 2つのネームスペースに分割 |
-dense/-compact 接尾辞が増殖 | ネームスペース分割のサイン |
| レスポンシブで値が変わるだけ | メディアクエリで対応(分割不要) |
| ライト/ダークテーマの切り替え | カラースキームで対応(分割不要) |
| 3つ以上の明確に異なるデザインコンテキスト | 3つ以上のネームスペースも可 |
AI がよくやるミス
- すべてのコンテキストを1つのネームスペースに押し込む —
-dense、-compact、-small接尾辞でトークンを区別しようとする。ネームスペースプレフィックスで分離すべき - ネームスペースを細かく分けすぎる — ページごとにネームスペースを作るのは過剰。デザイン原則が根本的に異なるコンテキスト間でのみ分割する
- 共有トークンを各ネームスペースに複製する — ブランドカラーやボーダー半径など、すべてのコンテキストで共通のトークンはプレフィックスなしの共有トークンとして定義する
- レスポンシブバリエーションをネームスペースで分ける — モバイル用/デスクトップ用でネームスペースを分けるのは誤り。レスポンシブはメディアクエリやコンテナクエリで対応する
- ネームスペースプレフィックスを省略する —
content-gapとcell-gapでは、どのコンテキスト用か分からない。必ずmyweb-content-gap、myadmin-cell-gapのようにプレフィックスを付ける
いつ使うか
適しているケース
- サイトが複数の明確に異なるデザインコンテキストを持つ — 記事サイト + 管理画面、ECサイト + 管理ダッシュボードなど
- 1つのトークンセットに
-dense/-compact接尾辞が増え始めた — ネームスペース分割のタイミング - 異なるチームが異なる画面を担当している — 各チームが自分のネームスペースを管理できる
不要なケース
- サイト全体が同じデザインルールで統一されている — 単一ネームスペースのタイトトークン戦略で十分
- 管理画面が別のアプリケーション — 別プロジェクトなら別の
@themeを持てばよい - 小規模サイト — トークン数が少なければ分割の必要はない
他のトークン戦略との関係
マルチネームスペーストークン戦略はタイトトークン戦略の拡張です。まずタイトトークン戦略でデフォルトをリセットし、その上で複数のネームスペースを定義します:
| 戦略 | 役割 |
|---|---|
| タイトトークン戦略 | デフォルトをリセットし、セマンティックトークンのみ定義 |
| マルチネームスペーストークン戦略 | デザインコンテキストごとにトークンを分離 |
| 2層サイズ戦略 | 幅・高さのサイジングルール |