design-system について
design-systemは、保守しやすいデザインシステムを構築するチーム向けのスキルです。既存のデザインコンテキストやコードを基に、トークン、コンポーネント、テーマを設計し、文書化と検証も扱います。
主な機能
- 01プリミティブ、セマンティック、コンポーネントのトークン階層
- 02CSS変数とテーマ上書きの整理
- 03コンポーネントのバリアント、サイズ、状態の定義
- 04スペーシング、シャドウ、角丸、動きの体系化
- 05コンポーネント文書とテーマ・コントラストの検証
活用シーン
- 01既存プロジェクトのトークンやコンポーネントの拡張
- 02コンポーネント間のテーマと状態表現の統一
- 03使用方法の記録と複数テーマでの表示確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ arnavpuri/ designskills --skill design-systemインストール後、Claude Code で/design-systemを入力して読み込まれたか確認します。
詳細
デザインシステム
トークン、コンポーネント、テーマ設定アーキテクチャを使用して、拡張性と保守性に優れたデザインシステムを構築します。
前提条件
デザインシステムを構築する前に、既存のデザインコンテキストを確認してください。
.agents/design-context.md(design-contextを参照)を読み、色、フォント、Base Size、Scale Ratio、Border Radius、Shadow Style、Spacing System を確認します。プリミティブトークンは、独自に作成した値ではなく、これらを基にする必要があります。- コードベースをスキャンして既存のトークン(CSS 変数、Tailwind テーマ、
tokens.json)を探し、それらを拡張します。 - コンポーネントのパターンを特定するため、フレームワーク(React、Vue、Svelte、vanilla)を確認します。
- 兄弟スキルが管理するものを再定義しないでください。色のスケールは
color-palette(--brand-*、--gray-*、--success-*、--warning-*、--error-*、--info-*)から、文字サイズのスケールはtypography(--text-xs…--text-5xl)から取得します。
ステップ 1:デザイントークンの階層
トークンはデザインシステムの最小単位となる値です。次の 3 層に構成します。
レイヤー 1:プリミティブトークン(生の値)
それが何であるかに基づいて名前を付けます。コンポーネント内で直接使用しないでください。
すべての生の値を :root で定義し、色には oklch を使用します。以下を含めます。
- 色:
--brand-50…950、--gray-50…950、セマンティックカラーの--success-*、--warning-*、--error-*、--info-*(color-palette から) - スペーシング:
--space-N= N × 4px、rem 単位(0、px、0.5、1、2、3、4、5、6、8、10、12、16、20、24) -- ステップ 6 を参照 - フォントサイズ:デザインコンテキストの Base Size × Scale Ratio から生成する
--text-xs…--text-5xl(typography スキル)。別のスケールをハードコードしないでください。 - 角丸:none、sm(0.25rem)、md(0.5rem)、lg(0.75rem)、xl(1rem)、2xl(1.5rem)、full(9999px)。md にはデザインコンテキストの Border Radius を設定します。
レイヤー 2:セマンティックトークン(目的)
何をするかに基づいて名前を付けます。これらはテーマの主要なインターフェースです。
:root でプリミティブを目的に対応付けます。
- 背景:
--bg-primary(gray-50)、--bg-secondary(white)、--bg-tertiary(gray-100)、--bg-inverse(gray-900) - テキスト:primary(gray-900)、secondary(gray-600)、tertiary(gray-400)、inverse、brand
- 境界線:default(gray-200)、strong(gray-300)、brand(brand-500)
- インタラクティブ要素:
--interactive-primary/-hover/-active(brand-500/600/700)、secondary/hover(gray スケール) - ブランドエイリアス:
--color-primary、--color-secondary、--color-accent(design-context が自動検出する名前) - セマンティックカラー:
--color-success(success-500)、--color-warning(warning-500)、--color-error(error-500) - スペーシング:gap-xs から gap-section までを space トークンに対応付けます。
- 角丸:button(md)、card(lg)、input(md)、badge(full)、modal(xl)
レイヤー 3:コンポーネントトークン(スコープ付き)
どこで使用されるかに基づいて名前を付けます。必須ではありませんが、複雑なシステムで効果を発揮します。
トークンのスコープを個々のコンポーネントに限定します。.btn の例では、セマンティックトークンを使用して --btn-padding-x、--btn-padding-y、--btn-radius、--btn-font-size、--btn-bg、--btn-color、--btn-border を定義し、同じルール内で使用します。バリアントでは、変更が必要なコンポーネントトークンのみを上書きします。
ステップ 2:CSS カスタムプロパティのアーキテクチャ
ファイル構成
tokens/
_primitives.css /* Layer 1: raw values */
_semantic.css /* Layer 2: purpose mappings */
_themes.css /* Theme overrides (dark mode, etc.) */
components/
_button.css
_card.css
_input.css
index.css /* Imports all */
インポート順序
/* index.css */
@import './tokens/_primitives.css';
@import './tokens/_semantic.css';
@import './tokens/_themes.css';
@import './components/_button.css';
@import './components/_card.css';
@import './components/_input.css';
データ属性によるスコープ設定
/* _themes.css */
[data-theme="dark"] {
--bg-primary: var(--gray-950);
--bg-secondary: var(--gray-900);
--bg-tertiary: var(--gray-800);
--text-primary: var(--gray-50);
--text-secondary: var(--gray-300);
--border-default: var(--gray-700);
--interactive-primary: var(--brand-400);
}
/* Follow the OS setting instead of (or as well as) a manual theme */
@media (prefers-contrast: more) {
:root { --text-secondary: var(--text-primary); --border-default: var(--gray-900); }
}
Windows のハイコントラストモード / forced-colors: active では、カスタムカラーがシステムカラーに置き換えられます。状態を背景色だけで伝えないでください。また、ボタンが常に表示されるように、透明な outline または border を維持してください。
トークンのエクスポート(W3C DTCG 形式)
ツール(Style Dictionary、Tokens Studio、Figma variables)でも使用できるよう、Design Tokens Community Group 形式の tokens.json も出力します。各トークンは $value と $type を持つオブジェクトです($type はグループに一度だけ設定できます)。エイリアスには {group.token} を使用し、メタデータは $description に格納します。安定版仕様(2025.10)では、構造化された色と寸法の値が使用されます。古いツールでは "#0F74C5" / "16px" のような文字列が必要な場合があるため、使用するツールがサポートする形式を確認してください。
{
"color": {
"$type": "color",
"brand": {
"500": { "$value": { "colorSpace": "oklch", "components": [0.55, 0.15, 250], "hex": "#0F74C5" } }
},
"interactive": {
"primary": { "$value": "{color.brand.500}", "$description": "Primary buttons, links" }
}
},
"space": {
"$type": "dimension",
"4": { "$value": { "value": 1, "unit": "rem" } }
},
"duration": {
"$type": "duration",
"normal": { "$value": { "value": 200, "unit": "ms" } }
},
"easing": {
"$type": "cubicBezier",
"out": { "$value": [0, 0, 0.2, 1] }
}
}
ステップ 3:コンポーネント API の設計
バリアント
バリアントには CSS クラスを使用します。サイズバリアント(--sm、--lg)はパディングとフォントサイズのトークンを上書きします。スタイルバリアント(--secondary、--ghost、--outline、--danger)は背景色、色、ボーダーのトークンのみを上書きします。
状態
すべてのインタラクティブコンポーネントには、次の状態が必要です。:hover(背景色を調整)、:active(背景色を暗くし、scale(0.98)を適用)、:focus-visible(背景に対してコントラスト比3:1となる2pxのアウトラインと2pxのオフセット)、:disabled/[aria-disabled="true"](不透明度を下げ、cursor: not-allowedを指定します。aria-disabledの場合はクリックもJSでブロックします。フォーカス可能なままにすることが重要です)。
一貫した API パターン
| プロパティ | オプション |
|---|---|
| サイズ | sm、md(デフォルト)、lg |
| バリアント | primary(デフォルト)、secondary、ghost、outline、danger |
| 状態 | default、hover、active、focus、disabled |
| 形状 | default、pill(radius-full) |
ステップ 4:コンポーザブルなコンポーネントパターン
カード(コンポーザブル)
パーツ:.card(ボーダー、角丸、オーバーフロー)、.card-header/.card-body/.card-footer(セマンティックトークンによるパディング。ヘッダーとフッターには区切り線のボーダーがあります)。.card-mediaにはaspect-ratio: 16/9; object-fit: coverを使用します。バリアント:--elevated(ボーダーの代わりにシャドウ)、--interactive(ホバー時にシャドウとtranslateYを適用)。
入力(完全版)
コンポーネントトークン(--input-height、--input-border、--input-radius、--input-bg)を使用します。デフォルトの高さは2.5remで、幅は100%です。状態::hover(ボーダーを強調)、:focus(ブランドカラーのボーダーと、不透明度0.15の3pxリング)、--error(エラーボーダー)。サイズ:--sm(2rem)、--lg(3rem)。
ステップ 5:テーマ設定のアーキテクチャ
テーマの切り替え
<html>にdata-theme属性を設定します。JSでは、まずlocalStorageを確認し、設定がなければprefers-color-scheme: darkメディアクエリを使用します。OSの変更を監視し、保存済みの設定がない場合は更新します。誤ったテーマが一瞬表示されるのを防ぐため、CSSの描画前に<head>内の小さなインライン<script>として実行し、フォームコントロールとスクロールバーの表示を合わせるためにcolor-scheme: light darkを設定します。
マルチブランドテーマ設定
[data-brand="name"]セレクターを使用して、レイヤー2のトークン(インタラクティブカラー、フォント)を再マッピングします。セマンティックトークンの値だけを変更することで、同じコンポーネントをブランドごとに異なる見た目で描画できます。
ステップ 6:スペーシングスケール
4pxを基本単位として使用します。--space-N = N × 4pxです。2pxのヘアラインを除き、すべての値は4の倍数です。design-contextで「8pxのベースグリッド」と指定されている場合も、このスケールは維持しつつ、レイアウトのスペーシングは偶数ステップ(2、4、6、8…)に限定します。layout-compositionでも同じスケールを使用します。
スケール
| トークン | 値 | rem | 用途 |
|---|---|---|---|
| 0.5 | 2px | 0.125 | ヘアラインの隙間 |
| 1 | 4px | 0.25 | コンポーネント内部の小さなパディング |
| 2 | 8px | 0.5 | アイコン間の隙間、コンパクトなパディング |
| 3 | 12px | 0.75 | ボタンのパディング、入力欄のパディング |
| 4 | 16px | 1 | カードのパディング、標準的な間隔 |
| 5 | 20px | 1.25 | カードのパディング(ゆとりあり) |
| 6 | 24px | 1.5 | セクション内部の間隔 |
| 8 | 32px | 2 | コンポーネントグループ間 |
| 10 | 40px | 2.5 | コンポーネント間の広いスペース |
| 12 | 48px | 3 | セクションのパディング |
| 16 | 64px | 4 | セクションのマージン |
| 20 | 80px | 5 | ヒーロー領域のパディング |
| 24 | 96px | 6 | 主要なセクション間の区切り |
使い分け
- コンポーネント内(アイコンとテキスト、ラベルと入力欄の間):space-1~space-3。
- 隣接するコンポーネント間(カード同士、入力フィールド同士):space-4~space-6。
- セクション間:space-12~space-24。
ステップ 7:シャドウ/エレベーションシステム
シャドウはエレベーションを示します。階層化されたシステムを構築します。
--shadow-xs から --shadow-2xl までの6段階を定義します。oklch(0 0 0 / opacity) のシャドウを複数レイヤーで使用し、ぼかしとオフセットを段階的に大きくします。
:root {
--shadow-sm: 0 1px 2px oklch(0 0 0 / 0.06), 0 1px 3px oklch(0 0 0 / 0.08);
--shadow-md: 0 2px 4px oklch(0 0 0 / 0.06), 0 4px 12px oklch(0 0 0 / 0.10);
--shadow-lg: 0 4px 8px oklch(0 0 0 / 0.06), 0 12px 32px oklch(0 0 0 / 0.14);
}
デザインコンテキストの Shadow Style に合わせて不透明度を調整します。none は境界線/サーフェスカラーのみ、subtle は上記の値とほぼ同じ、medium は約1.5倍、dramatic はオフセットを大きくして約2倍です。
| レベル | シャドウ | 用途 |
|---|---|---|
| 0 | なし | サーフェスと同じ高さ(デフォルト) |
| 1 | xs/sm | カード、ボタン |
| 2 | md | ドロップダウン、ポップオーバー |
| 3 | lg | モーダル、ドロワー |
| 4 | xl/2xl | トースト通知、エレベーションのあるモーダル |
ダークモードではシャドウの不透明度を高くする(0.3以上)か、代わりにサーフェスカラーの違いを利用します。
ステップ 8:ボーダーラディウスシステム
スケール:none(0)、sm(4px)、md(8px)、lg(12px)、xl(16px)、2xl(24px)、full(9999px)。
ネスト時のラディウスのルール:inner-radius = outer-radius - padding。計算結果が0以下の場合は、スケール上で1段階小さいサイズを使用します。
ステップ 9:トランジションとアニメーションのトークン
デュレーショントークン(--duration-fast:100ms、--duration-normal:200ms、--duration-slow:300ms、--duration-slower:500ms)とイージングトークン(--ease-out、--ease-in、--ease-in-out、--ease-spring)を定義します。名前と値は motion-design スキルと同じにします。デュレーションとイージングを組み合わせた複合トランジショントークン(--transition-colors、--transition-transform、--transition-shadow、--transition-opacity)を作成します。コンポーネントではこれらを組み合わせて使用します。例:ボタンでは var(--transition-colors), var(--transition-transform) を使用します。
必ず視差効果を減らす設定に対応します。
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
ステップ 10:コンポーネントのドキュメント作成パターン
コンポーネントのドキュメント作成
デザインシステムの各コンポーネントには、次の項目を含めます。
- 説明:コンポーネントの概要と使用する場面。
- バリエーション:視覚的なバリエーション(primary、secondary、ghost など)。
- サイズ:利用可能なサイズ(sm、md、lg)。
- 状態:インタラクティブな状態(hover、active、focus、disabled)。
- 構成:コンポーネントのパーツと、それぞれのトークン。
- 使用例/避ける例:使用ガイドライン。
- コード例:コピーしてそのまま使える HTML/CSS。
Storybook 形式の HTML ページを使用します。各コンポーネントは、説明を記載した <section> と、すべてのバリエーション、サイズ、状態を並べて表示する .doc-row コンテナ(flex wrap、gap、tertiary bg)で構成します。
ステップ 11:確認と保存
- ドキュメントページをレンダリングし(ステップ 10)、両方のテーマでスクリーンショットを撮影します:
npx playwright screenshot --full-page "file://$PWD/docs.html" light.pngを実行し、続けて--color-scheme=darkを指定する(またはdata-themeを切り替える)方法でも撮影します。Read で両方を確認します。すべてのバリエーション/サイズ/状態がレンダリングされること、フォーカスリングが見えること、disabled 状態が無効に見えること、コンポーネントでトークンの代わりに生の16進数カラーが使われていないことを確認します(grep -nE '#[0-9a-fA-F]{3,8}\b' components/)。 - 両方のテーマで、各テキスト/背景の組み合わせとボタンのコントラストを確認します(color-palette スキル内のスクリプトを使用します)。
- 変更されたプリミティブ(Color System hex、fonts、Base Size、Scale Ratio、Border Radius、Shadow Style、Spacing System)を
.agents/design-context.mdに書き戻すかどうかを尋ねます。変更した項目のみ更新します。差分を表示し、保存する前に確認を求めます。
クイックリファレンス:デザインシステムのチェックリスト
- プリミティブトークン(カラー、スペーシング、フォントサイズ、ラディウス)を定義します。
- セマンティックトークン(背景、テキスト、境界線、インタラクティブ)を対応付けます。
- データ属性を使用したテーマ設定を行います(最低限、ライト/ダークに対応)。
- 各コンポーネントにスコープされたコンポーネントトークンを作成します。
- コンポーネント API を設計します。サイズ(sm/md/lg)とバリエーションに一貫性を持たせます。
- すべてのインタラクティブな状態(hover、active、focus-visible、disabled)を実装します。
- 4px をスペーシングの基本単位として使用します。
- 5~6段階のシャドウシステムを構築します。
- アニメーションに一貫性を持たせるため、トランジショントークンを定義します。
- すべてのコンポーネントについて、バリエーション、サイズ、状態、例を含むドキュメントを作成します。