theme-colors について
UI 開発向けの配色スキルです。コンポーネントに色の直書きを避け、テーマの役割名を参照するよう定めています。役割の定義、透明度の扱い、例外、コードベースの監査手順を説明します。
主な機能
- 01テーマの役割名で色を指定
- 02alpha() による透明度の適用
- 03テーマ値を使ったグラデーション
- 04直書き色の監査と置き換え
- 05色の直書きが許される例外の確認
活用シーン
- 01コンポーネントの直書き色の整理
- 02ダークモード対応の配色構築
- 03グラデーションと透明オーバーレイの確認
- 04ブランドやデータ可視化向けのテーマ拡張
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ saschb2b/ skills --skill theme-colorsインストール後、Claude Code で/theme-colorsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
CARD.manifest.jsonCARD.mdCARD.md.sigstoreCARD.svgpermissions.yaml詳細
テーマカラー
ルール
すべての色はテーマから取得します。16 進数リテラル、rgba() 文字列、あちこちに散らばった値は使いません。
テーマでは、役割(primary、secondary、error、surface、text)ごとに色を一度だけ、1 か所で定義します。コンポーネントは値ではなく役割を参照します。ブランドの変更は 1 つのファイルを更新するだけで反映されます。ダークモードも、値が異なる同じテーマです。コンポーネントは alpha() ヘルパーを使って、役割の色から独自のホバー、不フォーカス、押下時の透明度を導き出します。
LLM が生成する UI で最もよくある失敗は、コンポーネントファイルに 16 進数コードが散在することです(color: "#3B82F6"、bgcolor: "#1E293B"、background: "rgba(255,255,255,0.5)")。学習コーパスの大半は、色をハードコードしたチュートリアルコードです。そのため、デフォルトの傾向は適切ではありません。
10 個の役割からなる用語体系
| 役割 | 意味 | 用途 |
|---|---|---|
primary | メインのブランドカラー | メインボタン、アクティブなタブ、重要な強調表示 |
secondary | 補完的なアクセントカラー | スイッチ、FAB、選択コントロール |
error | 問題や破壊的な操作を示します | エラーメッセージ、削除ボタン |
warning | エラーではないものの、注意が必要な状態です | 警告バナー、リスクのある操作の確認 |
info | 緊急性のない中立的な情報です | ツールチップ、情報バッジ、ヘルプテキスト |
success | 望ましい結果を示します | 成功通知、完了状態 |
background.default | ページの背景(「机」) | アプリの基本背景 |
background.paper | 高く持ち上げられたサーフェス(「机の上の紙」) | カード、ダイアログ、ドロップダウン、メニュー、ドロワー |
text.primary | 強調度の高いメインテキスト | 見出し、本文 |
text.secondary | 強調度を抑えたテキスト | キャプション、タイムスタンプ、補助テキスト |
各役割から .light、.dark、.contrastText が自動的に導き出されます。デフォルトを使い、具体的なコントラストやデザイン上の理由がある場合にのみ上書きしてください。
UI を記述する際のデフォルトの動作
次のようにします。
<Box sx={{ color: "text.primary", bgcolor: "background.paper" }}>
<Button color="primary">Save</Button>
</Box>
次のようにはしません。
<Box sx={{ color: "#1E293B", bgcolor: "#FFFFFF" }}>
<Button sx={{ bgcolor: "#3B82F6" }}>Save</Button>
</Box>
透明度には、リテラルの rgba() ではなく、テーマカラーに対して alpha() を使います。
import { alpha } from "@mui/material";
sx={(theme) => ({
bgcolor: alpha(theme.palette.secondary.main, 0.08),
})}
グラデーションなど、テーマ値を必要とする文字列型の CSS には、テーマを利用できる sx コールバック形式を使います。
sx={(theme) => ({
background: `linear-gradient(135deg, ${theme.palette.primary.main} 0%, ${theme.palette.accent.alt} 100%)`,
})}
16 進数リテラルを使ってよい 3 つの場所
- テーマ定義そのもの(
createTheme({ palette: { primary: { main: "#6366F1" } } }))。意図的に、16 進数値はテーマファイルに置きます。 - 標準の役割に当てはまらないカスタムパレット拡張:ブランド固有のアクセントや、意味を持つデータ可視化用パレット(例:金融分野の上昇を示す緑/下落を示す赤)などです。名前付きエントリーとしてテーマに追加し、コンポーネントから名前で参照します。
- インライン SVG フラグメント:色が外部アセット(ロゴ、アイコンライブラリ以外のアイコン)に属する場合です。リテラルはアセット自体の中に保持し、他のコンポーネントに同じ 16 進数を散在させないでください。
それ以外の場合は、すべてテーマトークンを使います。
監査ワークフロー
- コードベースを grep して色のリテラルを探します。
grep -rEn '(#[0-9a-fA-F]{3,8}|rgba?\(|hsla?\(|oklch\()' src/ app/ components/ - 各該当箇所を分類します。
- テーマファイル内または SVG 属性内にある場合は、そのままにします。
- それ以外の場所では、テーマトークンに置き換えます。
rgba(R, G, B, A)の場合、RGB 値が近似する役割を特定し、alpha(theme.palette.<role>.<variant>, A)に置き換えます。必要に応じてsxコールバックを使います。- リテラルのストップ値を持つグラデーションの場合、
sx={(theme) => ...}コールバックに移し、theme.palette.<role>.<variant>を補間します。 - インラインで使われている色名の場合(
color: "blue"、bg: "white")、最も近いテーマの役割に置き換えます。 - テーマにない「マジック」カラーの場合、インラインの上書きを追加しないでください。最も近い既存の役割に割り当てるか、名前付きエントリーをテーマに追加し、そこから参照します。
基本的な指針
- テーマカラーは不透明である必要があります。透明度はパレット定義ではなく、
alpha()を使ってコンポーネント側で指定します。あらかじめ薄くしたテーマカラーは、ホバー/フォーカス/押下時のオーバーレイと重なり、不自然に見えます。 - 具体的なコントラストやデザイン上の問題が見つかるまでは、
.light/.dark/.contrastTextを手動で上書きしないでください。デフォルト値は知覚的なコントラストに基づいて導出されます。 - ほとんどのアプリでは、10個のロールで十分です。30個のロールを持つパレットを追加すると、テーマが再び、手順が増えただけの16進数の値を並べた表になってしまいます。
出典
Why Developers Keep Asking for Primary Instead of Blue に基づいています。