ui-design について
コンポーネント、レイアウト、フォーム、レスポンシブ対応、アクセシビリティを扱う UI デザインスキルです。プロジェクトのデザインコンテキストを読み込み、スクリーンショットで表示を確認します。
主な機能
- 01アトミックデザインによる構成
- 02視覚的階層と操作状態の指針
- 03ナビゲーション、フォーム、フィードバックのパターン
- 04レスポンシブ対応とアクセシビリティの指針
- 05スクリーンショットによる表示確認
活用シーン
- 01ページのコンポーネントと視覚的階層の計画
- 02フォームや読み込み・エラー状態の設計
- 03モバイルとデスクトップのレイアウト確認
MCP 対応
Figma URL が提示された場合、Figma MCP の get_design_context と get_screenshot を使ってデザインコンテキストとスクリーンショットを取得する手順があります。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ arnavpuri/ designskills --skill ui-designインストール後、Claude Code で/ui-designを入力して読み込まれたか確認します。
詳細
UI デザインパターン
始める前に:デザインコンテキストを読み込む
.agents/design-context.mdを読みます(design-contextスキルによって作成されます)。ファイルがない場合は、tailwind.config.*または:rootの CSS 変数でトークンを探します。何も見つからない場合は、デフォルト(Primary#2563EB、Secondary#7C3AED、Accent#F59E0B、Tailwind のグレーニュートラル、見出しと本文には Inter、Minimal スタイル)を使用し、デフォルトを使用したことをユーザーに伝えます —design-contextの実行を提案してください。- トークンを一度 CSS 変数に対応付け、以降は変数のみを使用します:
--color-primary、--color-primary-light、--color-primary-dark、--color-secondary、--color-accent、--color-neutral-50…--color-neutral-900、--color-success/-warning/-error、--font-heading、--font-body、--font-mono、--radius、および 4px を基準とするスペーシングスケール。 - Tailwind: 同じ変数を
primary、primary-light、primary-dark、secondary、accent、neutral-*、font-heading、font-bodyとして公開します(v3 はtheme.extend、v4 は@theme)。以下の例にあるindigo-*/gray-*クラスは、これらのトークンのプレースホルダーです。 - Figma: ユーザーから Figma URL が提供された場合は、Figma MCP(
get_design_context、get_screenshot)で取得して再現します。そのデザインでは、デザインコンテキストファイルよりも Figma の内容を優先します。 - 半径、シャドウの深さ、セクション 9(トレンド)をどの程度使用するかは、スタイルアーキタイプに従います — Minimal と Corporate では使用しません。
1. コンポーネント設計の原則(Atomic Design)
UI はレイヤーごとに構築します。いきなりページ全体から始めず、最小のパーツから始めてください。
階層
- トークン — 色、スペーシング、角丸、シャドウ、タイポグラフィのスケール
- アトム — ボタン、入力欄、バッジ、アバター、アイコン
- モレキュール — 検索バー(入力欄 + ボタン)、フォームフィールド(ラベル + 入力欄 + エラー)、カードヘッダー(アバター + 名前 + タイムスタンプ)
- オーガニズム — ナビゲーションバー、ヒーローセクション、コメントスレッド、料金表
- テンプレート — オーガニズムで構成されたページレイアウト
- ページ — 実際のデータを使ったテンプレート
ルール
- 各コンポーネントには、ルートにスコープされた独自の CSS カスタムプロパティを持たせます。
- 設定よりもコンポジションを優先します。15 個の props を持つ
Cardより、childrenを持つCardの方が適しています。 - コンポーネントはデフォルトでステートレスにします。状態は親に持たせます。
/* Token layer — values come from .agents/design-context.md (defaults shown) */
:root {
--color-primary: #2563EB;
--color-surface: #FFFFFF;
--radius-md: 0.75rem;
--shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.05);
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-12: 3rem;
--space-16: 4rem;
}
標準スペーシングスケール(すべての UI スキルで共通): 4px を基準とします — 4、8、12、16、24、32、48、64px(Tailwind の 1, 2, 3, 4, 6, 8, 12, 16)。スケール外の値は使わないでください。
2. 視覚的階層のフレームワーク
視線の誘導をコントロールします。すべての要素の重要度を順位付けし、次の手段を適用します。
| 手段 | 強調 | 中程度の強調 | 弱い強調 |
|---|---|---|---|
| サイズ | 2rem 以上の見出し | 1rem の本文 | 0.75rem のキャプション |
| ウェイト | 700–800 の太字 | 500 のミディアム | 400 のレギュラー |
| 色 | プライマリ、またはコントラストの高いテキスト | 控えめなテキスト(neutral-600) | 目立たないテキスト(neutral-500 — 白地でコントラスト比 4.5:1 を満たす最も明るいグレー) |
| スペーシング | 周囲により広い余白 | 標準的なスペーシング | 狭めのスペーシング |
| 位置 | 左上または中央 | ページ中ほど | 下部またはサイドバー |
目を細めるテスト
目を細めるか、表示を 25% に縮小します。それでも主要なアクションとメインの見出しを見分けられれば、階層設計は機能しています。
Tailwind の実装
<h1 class="text-4xl font-extrabold tracking-tight text-gray-950">
Ship faster with AI
</h1>
<p class="mt-4 text-lg text-gray-600 max-w-2xl">
Build production-ready components in minutes, not hours.
</p>
<span class="text-xs text-gray-500 uppercase tracking-wide">
Updated 2 hours ago
</span>
3. インタラクティブな状態
すべてのインタラクティブ要素に、5 つの状態すべてが必要です。例外はありません。
状態の定義
.btn-primary {
/* Default */
background: var(--color-primary);
color: white;
border-radius: var(--radius-md);
padding: var(--space-2) var(--space-4);
font-weight: 600;
transition: background-color 150ms ease, box-shadow 150ms ease, transform 150ms ease, filter 150ms ease;
/* Hover — subtle lift or brightness shift */
&:hover {
filter: brightness(1.1);
box-shadow: 0 4px 12px oklch(0% 0 0 / 0.15);
transform: translateY(-1px);
}
/* Active — pressed feel */
&:active {
transform: translateY(0);
filter: brightness(0.95);
box-shadow: var(--shadow-sm);
}
/* Focus — visible ring for keyboard users */
&:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
/* Disabled — dimmed, no hover/active effects (don't add pointer-events: none — it hides the not-allowed cursor) */
&:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
box-shadow: none;
filter: none;
}
}
Tailwind の短縮記法
<button class="bg-indigo-600 text-white px-4 py-2 rounded-lg font-semibold
hover:bg-indigo-500 hover:-translate-y-0.5 hover:shadow-lg
active:translate-y-0 active:bg-indigo-700
focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600
disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
transition-all duration-150">
Click me
</button>
4. フィードバックパターン
読み込み状態
- スピナーよりもスケルトンスクリーンを使います。これから表示されるコンテンツの形を示します。
- プレースホルダーブロックには
motion-safe:animate-pulseを使い、領域にaria-busy="true"を指定して、sr-only の「読み込み中…」ラベルを付けます。 - 読み込み状態は、それを開始したアクションの近くにインラインで表示します。
<div class="motion-safe:animate-pulse space-y-3" aria-busy="true">
<span class="sr-only">Loading…</span>
<div class="h-48 bg-gray-200 rounded-xl"></div>
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
<div class="h-4 bg-gray-200 rounded w-1/2"></div>
</div>
成功状態
- 緑のアクセント、チェックマークのアイコン、簡潔な確認メッセージを使います。
role="status"(ポライトなライブリージョン)で通知します。5 秒以上経過したら自動的に閉じます。ただし、アクションを含むメッセージは自動的に閉じないでください。
エラー状態
- 赤をアクセントにし、内容がわかるメッセージと復旧方法を示します。
- 単に「エラー」とだけ表示しないでください。何が問題で、どうすればよいかを伝えます。
- 赤色だけに頼らず、アイコンとテキストを組み合わせます。送信後に表示されるエラーには
role="alert"を使用します。
空の状態
- イラストまたはアイコン、説明、解決するための主要なアクションを表示します。
<div class="text-center py-16">
<svg class="mx-auto h-12 w-12 text-gray-400" aria-hidden="true"></svg>
<h3 class="mt-4 text-lg font-semibold text-gray-900">No messages yet</h3>
<p class="mt-2 text-sm text-gray-500">Start a conversation to see messages here.</p>
<button type="button" class="mt-6 bg-indigo-600 text-white px-4 py-2 rounded-lg">
New message
</button>
</div>
5. ナビゲーションパターン
サイドバーナビゲーション
- 幅:デスクトップでは240~280px、アイコンのみの64px幅に折りたたみ可能にします。
- 控えめなセクション見出しを使って、項目をカテゴリ別にまとめます。
- アクティブな項目:塗りつぶしの背景、太字、左側のアクセントバーを使用し、
aria-current="page"を設定します。
トップナビゲーション
- 上部に固定または粘着表示します。高さは56~64pxです。
- ロゴは左、ナビゲーションリンクは中央または左、アクションは右に配置します。
- モバイルでは、
mdブレークポイントでハンバーガーメニューに切り替えます。
タブ
- 同じコンテキスト内でビューを切り替える場合に使用します。
- アクティブなタブ:プライマリカラーの下線(2~3px)と太字を使用します。
aria-selectedと矢印キーによるナビゲーションを備えたrole="tablist"/role="tab"を使用します(各タブがそれぞれ独自の URL を持つ場合は、通常のリンクでもかまいません)。 - タブは7つを超えないようにします。それ以上の場合は、ドロップダウンで残りを表示します。
パンくずリスト
- 区切り文字として
/または>を使用します。 - 現在のページはリンクではなく、テキストとして表示します。
- パスが長い場合は、途中の項目を省略表示します。
6. フォームのデザイン
ルール
- ラベルは入力欄の上に配置します。フローティング表示や横並びにはしません。常に表示します。
- 1列にします。複数列のフォームは完了率を低下させます。
- 関連するフィールドをまとめ、控えめなセクション区切りを入れます。
- インラインで検証します。入力のたびではなく、フォーカスが外れたときに検証します。
- エラーメッセージはフィールドの下に、赤色で具体的な対処方法とともに表示します。
- 主要なアクションはフォーム下部の左側に配置します。二次アクションはテキストリンクにします。
<div class="space-y-1.5">
<label for="email" class="block text-sm font-medium text-gray-700">
Email address
</label>
<input
type="email"
id="email"
class="block w-full rounded-lg border border-gray-300 px-3 py-2
text-gray-900 placeholder:text-gray-400
focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20
transition-colors"
placeholder="[email protected]"
autocomplete="email"
aria-describedby="email-error"
/>
<p id="email-error" class="text-sm text-red-600 hidden">Please enter a valid email address.</p>
</div>
7. デザインとしてのアクセシビリティ
アクセシビリティは後付けではありません。最初から適用するデザイン上の制約です。
コントラスト
- 通常のテキスト:最小コントラスト比は4.5:1(WCAG 2.2 AA)。
- 大きなテキスト(通常の太さで24px以上、または太字で18.66px以上):最小コントラスト比は3:1です。
- テキスト以外のUI(入力欄の境界線、アイコン、フォーカスリング、チャートのマーク):隣接する色とのコントラスト比を3:1以上にします。
- プレースホルダーテキストはラベルではありませんが、情報を伝える場合は4.5:1以上のコントラスト比を確保します。
- 知覚的に均一なコントラスト調整には、oklch色空間を使用します。
フォーカスインジケーター
- 置き換えずに
outlineを削除してはいけません。 - マウスクリック時にリングが表示されないよう、
focusではなくfocus-visibleを使用します。 - リング:2pxの実線、2pxのオフセット、プライマリカラーを使い、背景とのコントラスト比を3:1にします。
- フォーカスされた要素が固定ヘッダーやフッターの背後に隠れないようにします(WCAG 2.4.11)。ヘッダーの高さに等しい値を
scroll-padding-topに設定します。
ターゲットサイズ
- WCAG 2.5.8(AA):ポインターのターゲットは少なくとも 24×24 CSS px にします(または、直径24pxの円が隣のターゲットと重ならない間隔を設けます)。
- タッチ操作に関するプラットフォームのガイダンス:44×44pt(Apple HIG)、48×48dp(Material)。主要なタッチターゲットには44px以上を使用します。
セマンティック構造
- ページごとに
<h1>を1つだけ使用します。 - 見出しは順番どおりに使用します(
h1>h2>h3)。レベルを飛ばしてはいけません。 - ランドマークには
<nav>、<main>、<aside>、<footer>を使用します。 - アクションにはボタン、ナビゲーションにはリンクを使います。
<div onclick>は使用しないでください。 - アイコンのみのボタンには
aria-labelを設定します。
動き
@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;
}
}
8. レスポンシブブレークポイント戦略
ブレークポイント(Tailwindのデフォルト — すべてのUIスキルで標準として使用)
| 名前 | 幅 | 対象 |
|---|---|---|
sm | 640px | 横向きの大型スマートフォン |
md | 768px | タブレット |
lg | 1024px | 小型ノートPC |
xl | 1280px | デスクトップ |
2xl | 1536px | 大型画面 |
モバイルファーストのルール
- モバイルのレイアウトから始めます。大きなブレークポイントで複雑さを加えます。
- モバイルでは列を縦に並べ、
md以上では横に並べます。 md未満では、ナビゲーションをハンバーガーメニューにします。- フォントサイズを段階的に大きくします:
text-2xl md:text-4xl lg:text-5xl。 - モバイルではタッチ操作の余白を十分に確保します:
p-4。デスクトップでは狭くします:lg:p-2。
コンテナクエリ(モダンCSS)
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
9. モダンなUIトレンド
グラスモーフィズム
.glass {
background: oklch(100% 0 0 / 0.1);
backdrop-filter: blur(16px) saturate(180%);
border: 1px solid oklch(100% 0 0 / 0.15);
border-radius: 1rem;
}
グラスモーフィズムは情報量の多い背景の上でのみ機能します。背後の 最も明るい 領域に対するテキストのコントラストを確認し、次のように不透明なフォールバックを用意してください:@supports not (backdrop-filter: blur(1px)) { .glass { background: oklch(20% 0.02 265 / 0.9); } }。
Bento グリッド
.bento {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: minmax(200px, auto); /* fixed 200px rows clip long content */
gap: 1rem;
}
@media (max-width: 767px) { .bento { grid-template-columns: 1fr; } .bento .featured { grid-column: auto; grid-row: auto; } }
.bento .featured {
grid-column: span 2;
grid-row: span 2;
}
オーロラ/メッシュグラデーションの背景
.aurora {
background: linear-gradient(135deg, oklch(85% 0.15 280), oklch(80% 0.2 320), oklch(75% 0.18 200));
background-size: 400% 400%;
animation: aurora-shift 8s ease infinite;
}
@keyframes aurora-shift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
10. 高度な CSS テクニック
:has() — 親セレクター
/* Highlight form group when input is focused */
.form-group:has(input:focus-visible) {
background: oklch(97% 0.01 265);
border-color: var(--color-primary);
}
/* Card changes layout when it contains an image */
.card:has(img) {
grid-template-rows: 200px 1fr;
}
サブグリッド
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3; /* header, body, footer align across cards */
}
スクロール駆動アニメーション
/* Progressive enhancement: only where supported and motion is OK */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.fade-in {
animation: fade-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}
}
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(2rem); }
to { opacity: 1; transform: translateY(0); }
}
検証:レンダリングして確認する
確認していないコードを引き渡さないでください。生成したら、次の手順を実行します。
- モバイルとデスクトップの幅でスクリーンショットを撮ります。例:
npx playwright screenshot --full-page --viewport-size=390,844 file://$PWD/index.html mobile.pngを実行し、続けて--viewport-size=1440,900を指定します(または開発サーバーの URL を指定します)。 - 画像を両方開き、水平スクロールやテキストの切り抜き・重なりがないこと、階層がひと目でわかること、ブランドのトークンが適用されていること、画像が適切なアスペクト比で読み込まれていることを確認します。
- 一度 Tab キーで順に移動し、すべてのインタラクティブ要素に論理的な順序で視認できるフォーカスリングが表示されることを確認します。
- 作成したすべての状態(ホバー、フォーカス、無効、読み込み中、空、エラー)を少なくとも一度確認し、ミュートされたテキストのコントラストをチェックします。
- 問題が見つかったら修正し、完了を報告する前にもう一度スクリーンショットを撮ります。
クイックリファレンス:デザインチェックリスト
UI コンポーネントをリリースする前に、次の項目を確認します。
- 視覚的な階層が明確である(目を細めて見るテストに合格する)
- すべてのインタラクティブ要素にホバー、アクティブ、フォーカス可視、無効の各状態がある
- 色のコントラストが WCAG 2.2 AA を満たしている(テキストは 4.5:1、大きなテキストと UI コンポーネントは 3:1)
- ターゲットのサイズが 24×24px 以上である(主要なタッチターゲットは 44px 以上)
- 390px と 1440px でレンダリングし、スクリーンショットを撮影している(「検証」を参照)
- フォーカス順序が論理的である(ページ内を Tab キーで移動して確認する)
- すべてのブレークポイントでレスポンシブに対応している(320px から 1920px)
- 読み込み中、空、エラーの各状態がデザインされている
- スペーシングに 4px 基準のスケールを使用している(4、8、12、16、24、32、48、64)
- タイポグラフィのスケールが 4~6 サイズに制限されている
- モーションが
prefers-reduced-motionに準拠している - セマンティック HTML を使用している(ランドマーク、見出し、ボタンとリンクの使い分け)