mcpField
A
apple-hig-designer

apple-hig-designer

github.com/jamesrochabrunデザイン・UI2211.1k 回インストール41 週間前に更新
リポジトリ

apple-hig-designer について

apple-hig-designerは、iOSのデザイナーや開発者向けのスキルです。Apple Human Interface Guidelinesに沿った画面の作成と確認を、ネイティブコンポーネントやアクセシビリティの観点から支援します。

主な機能

  1. 01SwiftUIとUIKitのコンポーネント生成
  2. 02Apple HIGへの準拠確認
  3. 03VoiceOverとDynamic Typeへの対応
  4. 04セマンティックカラーとダークモード
  5. 05タイポグラフィ、余白、安全領域の指針

活用シーン

  1. 01ネイティブなiOS画面の構築
  2. 02画面のアクセシビリティ対応確認
  3. 03ライト・ダーク表示の配色設計

インストール

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

$npx skills add https://github.com/jamesrochabrun/skills --skill apple-hig-designer

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
accessibility.md
colors.md
components.md
layout_spacing.md
typography.md
scripts/
audit_accessibility.sh
generate_ios_component.sh
validate_design.sh

詳細

Apple HIG デザイナー

AppleのHuman Interface Guidelines(HIG)に沿って、美しくネイティブなiOSアプリをデザインします。ネイティブコンポーネント、適切なタイポグラフィ、セマンティックカラー、Appleのデザイン原則を活用して、アクセシブルで直感的なインターフェイスを作成します。

このスキルでできること

Appleのガイドラインに沿った、ネイティブな使い心地のiOSアプリのデザインと構築を支援します。

  • iOSコンポーネントを生成 - SwiftUIおよびUIKitのコンポーネントを作成します
  • デザインを検証 - Apple HIGへの準拠を確認します
  • アクセシビリティを確保 - VoiceOver、Dynamic Type、色のコントラストに対応します
  • デザイン原則を適用 - 明瞭性、従属性、奥行きを取り入れます
  • セマンティックカラーを使用 - ダークモードを自動的にサポートします
  • タイポグラフィを実装 - San Franciscoフォントシステムを使用します
  • スペーシングに準拠 - 8ptグリッドシステムとセーフエリアを使用します

Appleのデザイン原則

1. 明瞭性

コンテンツを明確に、焦点を絞って表示します。

どのサイズでも読みやすいテキスト、正確で明快なアイコン、控えめで適切な装飾を用い、機能性を重視してデザインします。

// ✅ Clear, focused content
Text("Welcome back, Sarah")
    .font(.title)
    .foregroundColor(.primary)

// ❌ Unclear, cluttered
Text("Welcome back, Sarah!!!")
    .font(.title)
    .foregroundColor(.red)
    .background(.yellow)
    .overlay(Image(systemName: "star.fill"))
2. 従属性

UIは、コンテンツの理解と操作を支援しますが、コンテンツと競合することはありません。

コンテンツを最優先し、軽やかなビジュアル表現を用いて、コンテンツに焦点を保ち、ゆとりを持たせます。

// ✅ Content-focused
VStack(alignment: .leading, spacing: 8) {
    Text("Article Title")
        .font(.headline)
    Text("Article content goes here...")
        .font(.body)
        .foregroundColor(.secondary)
}
.padding()

// ❌ Distracting UI
VStack(spacing: 8) {
    Text("Article Title")
        .font(.headline)
        .foregroundColor(.white)
        .background(.blue)
        .border(.red, width: 3)
}
3. 奥行き

視覚的なレイヤーと現実感のある動きによって、階層を伝え、関係性の理解を促します。

明確な視覚的レイヤーと現実感のある動きが活気を与え、理解を促します。タッチ操作と見つけやすさによって楽しさを高め、コンテキストを失わずに機能へアクセスできるようにします。

// ✅ Clear depth hierarchy
ZStack {
    Color(.systemBackground)

    VStack {
        // Card with elevation
        CardView()
            .shadow(radius: 8)
    }
}

// Using blur for depth
Text("Content")
    .background(.ultraThinMaterial)

iOS UIコンポーネント

ナビゲーションパターン
1. ナビゲーションバー

ナビゲーションとアクションのためのトップバーです。

NavigationStack {
    List {
        Text("Item 1")
        Text("Item 2")
    }
    .navigationTitle("Title")
    .navigationBarTitleDisplayMode(.large)
    .toolbar {
        ToolbarItem(placement: .navigationBarTrailing) {
            Button("Add") {
                // Action
            }
        }
    }
}

ガイドライン:

  • 最上位の画面では大きなタイトルを使用します
  • 詳細画面ではインラインタイトルを使用します
  • アクションは現在のコンテキストに関連するものにします
  • ツールバー項目は最大2~3個にします
2. タブバー

最上位の画面遷移に使う下部ナビゲーションです。

TabView {
    HomeView()
        .tabItem {
            Label("Home", systemImage: "house")
        }

    SearchView()
        .tabItem {
            Label("Search", systemImage: "magnifyingglass")
        }

    ProfileView()
        .tabItem {
            Label("Profile", systemImage: "person")
        }
}

ガイドライン:

  • タブは最大3~5個にします
  • アイコンにはSF Symbolsを使用します
  • ラベルは簡潔にします(1語)
  • タブを非表示にしたり、無効にしたりしないでください
  • 同じ画面でタブバーとツールバーを併用しないでください
3. リスト

スクロール可能な項目の一覧です。

List {
    Section("Today") {
        ForEach(items) { item in
            NavigationLink {
                DetailView(item: item)
            } label: {
                HStack {
                    Image(systemName: item.icon)
                        .foregroundColor(.accentColor)
                    Text(item.title)
                }
            }
        }
    }
}
.listStyle(.insetGrouped)

リストのスタイル:

  • .plain - 端から端まで表示する行
  • .insetGrouped - 角丸でインセットされたセクション(iOSのデフォルト)
  • .sidebar - ナビゲーションサイドバー用
4. シート(モーダル)

コンテンツをモーダル表示します。

struct ContentView: View {
    @State private var showSheet = false

    var body: some View {
        Button("Show Details") {
            showSheet = true
        }
        .sheet(isPresented: $showSheet) {
            DetailView()
                .presentationDetents([.medium, .large])
        }
    }
}

シートの表示高さ:

  • .medium - 画面の半分
  • .large - 全画面
  • カスタムの高さも指定できます
フォームコントロール
1. ボタン

主要なアクションを実行するコントロールです。

// Filled button (primary action)
Button("Continue") {
    // Action
}
.buttonStyle(.borderedProminent)

// Bordered button (secondary action)
Button("Cancel") {
    // Action
}
.buttonStyle(.bordered)

// Plain button (tertiary action)
Button("Learn More") {
    // Action
}
.buttonStyle(.plain)

ボタンの階層:

  1. 目立つボタン - 主要なアクション(画面ごとに1つ)
  2. 枠線付き - 二次的なアクション
  3. プレーン - 三次的なアクションやリンク

ガイドライン:

  • タップ可能な領域は最低44x44ポイントにします
  • ボタンのラベルには動詞を使います
  • 破壊的なアクションには確認を必要とします
2. TextField

テキスト入力コントロールです。

@State private var username = ""
@State private var password = ""

VStack(alignment: .leading, spacing: 16) {
    // Standard text field
    TextField("Username", text: $username)
        .textFieldStyle(.roundedBorder)
        .textContentType(.username)
        .textInputAutocapitalization(.never)
        .autocorrectionDisabled()

    // Secure field
    SecureField("Password", text: $password)
        .textFieldStyle(.roundedBorder)
        .textContentType(.password)
}

テキストコンテンツタイプ:

  • .username - ユーザー名フィールド
  • .password - パスワードフィールド
  • .emailAddress - メールアドレスフィールド
  • .telephoneNumber - 電話番号
  • .creditCardNumber - クレジットカード番号
3. Toggle

ブール値を切り替えるコントロール(スイッチ)です。

@State private var isEnabled = false

Toggle("Enable notifications", isOn: $isEnabled)
    .toggleStyle(.switch)

ガイドライン:

  • ラベルで切り替えの対象を説明します
  • 切り替えの効果は即座に反映します
  • 2択の場合にのみ使用します
4. Picker

選択用のコントロールです。

@State private var selectedSize = "Medium"
let sizes = ["Small", "Medium", "Large"]

// Menu style
Picker("Size", selection: $selectedSize) {
    ForEach(sizes, id: \.self) { size in
        Text(size).tag(size)
    }
}
.pickerStyle(.menu)

// Segmented style (for 2-5 options)
Picker("Size", selection: $selectedSize) {
    ForEach(sizes, id: \.self) { size in
        Text(size).tag(size)
    }
}
.pickerStyle(.segmented)

Pickerのスタイル:

  • .menu - ドロップダウンメニュー(デフォルト)
  • .segmented - セグメントコントロール(選択肢は2~5個)
  • .wheel - スクロールホイール
  • .inline - インラインリスト(フォーム内)
カードとコンテナ
カードビュー
struct CardView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Title")
                .font(.headline)

            Text("Description goes here with some details about the content.")
                .font(.subheadline)
                .foregroundColor(.secondary)
                .lineLimit(2)

            Spacer()

            Button("Action") {
                // Action
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
        .frame(width: 300, height: 200)
        .background(Color(.systemBackground))
        .cornerRadius(12)
        .shadow(color: .black.opacity(0.1), radius: 8, x: 0, y: 4)
    }
}

タイポグラフィ

San Franciscoフォントシステム

読みやすさを最適化するために設計されたAppleのシステムフォントです。

// Dynamic Type text styles
Text("Large Title").font(.largeTitle)      // 34pt
Text("Title").font(.title)                 // 28pt
Text("Title 2").font(.title2)              // 22pt
Text("Title 3").font(.title3)              // 20pt
Text("Headline").font(.headline)           // 17pt semibold
Text("Body").font(.body)                   // 17pt regular
Text("Callout").font(.callout)             // 16pt
Text("Subheadline").font(.subheadline)     // 15pt
Text("Footnote").font(.footnote)           // 13pt
Text("Caption").font(.caption)             // 12pt
Text("Caption 2").font(.caption2)          // 11pt
Dynamic Typeでカスタムフォントを使用する
// Custom font that scales with Dynamic Type
Text("Custom Text")
    .font(.custom("YourFont-Regular", size: 17, relativeTo: .body))
フォントのウェイト
Text("Light").fontWeight(.light)
Text("Regular").fontWeight(.regular)
Text("Medium").fontWeight(.medium)
Text("Semibold").fontWeight(.semibold)
Text("Bold").fontWeight(.bold)
Text("Heavy").fontWeight(.heavy)
タイポグラフィのガイドライン

推奨事項:

  • ✅ 一貫性を保つため、システムフォント(San Francisco)を使用します
  • ✅ アクセシビリティのため、Dynamic Type に対応します
  • ✅ セマンティックなテキストスタイル(.headline、.body など)を使用します
  • ✅ 本文の最小サイズは 17pt にします
  • ✅ 行間はフォントサイズの 120~145%にします

禁止事項:

  • ❌ フォントサイズを増やしすぎないでください(システムスタイルを使用します)
  • ❌ テキストを 11pt 未満にしないでください
  • ❌ 長いテキストにすべて大文字を使用しないでください
  • ❌ Dynamic Type を無効にしないでください

色

セマンティックカラー

ライトモード/ダークモードに自動的に適応する色です。

// UI Element Colors
Color(.label)                    // Primary text
Color(.secondaryLabel)           // Secondary text
Color(.tertiaryLabel)            // Tertiary text
Color(.quaternaryLabel)          // Watermark text

Color(.systemBackground)         // Primary background
Color(.secondarySystemBackground) // Secondary background
Color(.tertiarySystemBackground)  // Tertiary background

Color(.systemFill)               // Fill colors
Color(.secondarySystemFill)
Color(.tertiarySystemFill)
Color(.quaternarySystemFill)

Color(.separator)                // Separator lines
Color(.opaqueSeparator)          // Non-transparent separator
システムカラー
// Standard system colors (adapt to dark mode)
Color(.systemRed)
Color(.systemOrange)
Color(.systemYellow)
Color(.systemGreen)
Color(.systemMint)
Color(.systemTeal)
Color(.systemCyan)
Color(.systemBlue)
Color(.systemIndigo)
Color(.systemPurple)
Color(.systemPink)
Color(.systemBrown)
Color(.systemGray)
ダークモード対応のカスタムカラー
// Define adaptive color
extension Color {
    static let customBackground = Color("CustomBackground")
}

// In Assets.xcassets, create color set with:
// - Any Appearance: #FFFFFF
// - Dark Appearance: #000000
色のコントラストに関するガイドライン

WCAG AA 準拠:

  • 通常のテキスト:コントラスト比は最低 4.5:1
  • 大きなテキスト(24pt 以上):コントラスト比は最低 3:1
  • UI コンポーネント:コントラスト比は 3:1

カスタムカラー:

  • コントラストを上げる設定を有効にしてテストします
  • 重要なテキストでは 7:1 を目指します
  • どちらのモードでも十分なコントラストを確保します

間隔とレイアウト

8 ポイントグリッドシステム

すべての間隔を 8 の倍数にします。

// Spacing values
.padding(8)      // 8pt
.padding(16)     // 16pt (standard)
.padding(24)     // 24pt
.padding(32)     // 32pt
.padding(40)     // 40pt
.padding(48)     // 48pt

// Edge-specific padding
.padding(.horizontal, 16)
.padding(.vertical, 24)
.padding(.top, 16)
.padding(.bottom, 16)
セーフエリア

デバイスのセーフエリアを尊重します。

// Content within safe area (default)
VStack {
    Text("Content")
}

// Extend beyond safe area
VStack {
    Color.blue
}
.ignoresSafeArea()

// Extend top only
VStack {
    Color.blue
}
.ignoresSafeArea(edges: .top)
タッチターゲット

インタラクティブ要素の最小サイズは 44x44 ポイントです。

Button("Tap") {
    // Action
}
.frame(minWidth: 44, minHeight: 44)
間隔に関するガイドライン
// Component spacing
VStack(spacing: 8) {       // Tight spacing
    Text("Line 1")
    Text("Line 2")
}

VStack(spacing: 16) {      // Standard spacing
    Text("Section 1")
    Text("Section 2")
}

VStack(spacing: 24) {      // Loose spacing
    SectionView()
    SectionView()
}

アクセシビリティ

VoiceOver のサポート

視覚障害のあるユーザーや弱視のユーザー向けのスクリーンリーダーです。

// Accessible label
Image(systemName: "heart.fill")
    .accessibilityLabel("Favorite")

// Accessible value
Slider(value: $volume)
    .accessibilityLabel("Volume")
    .accessibilityValue("\(Int(volume * 100))%")

// Accessible hint
Button("Share") {
    share()
}
.accessibilityHint("Shares this item with others")

// Group elements
HStack {
    Image(systemName: "person")
    Text("John Doe")
}
.accessibilityElement(children: .combine)

// Hidden from VoiceOver
Image("decorative")
    .accessibilityHidden(true)
Dynamic Type

ユーザーが希望するテキストサイズに対応します。

// Automatically supported with system fonts
Text("This text scales")
    .font(.body)

// Limit scaling (if necessary)
Text("This text has limits")
    .font(.body)
    .dynamicTypeSize(...DynamicTypeSize.xxxLarge)

// Custom font with Dynamic Type
Text("Custom font")
    .font(.custom("YourFont", size: 17, relativeTo: .body))
色覚特性

色覚特性のあるユーザーに配慮して設計します。

// Don't rely on color alone
HStack {
    Image(systemName: "checkmark.circle.fill")
        .foregroundColor(.green)
    Text("Success")
}

// Not just color
Circle()
    .fill(.green)
// ❌ Color only

// Better with shape/icon
HStack {
    Image(systemName: "checkmark.circle.fill")
    Circle().fill(.green)
}
// ✅ Color + shape
モーションを減らす

ユーザーのモーションに関する設定を尊重します。

@Environment(\.accessibilityReduceMotion) var reduceMotion

var animation: Animation {
    reduceMotion ? .none : .spring()
}

Button("Animate") {
    withAnimation(animation) {
        // Animate
    }
}
コントラストを上げる

ハイコントラストモードに対応します。

@Environment(\.colorSchemeContrast) var contrast

var textColor: Color {
    contrast == .increased ? .primary : .secondary
}

Text("Content")
    .foregroundColor(textColor)

ダークモード

ライトモードとダークモードの両方に対応します。

自動対応
// Use semantic colors (automatic)
Color(.label)                // Adapts automatically
Color(.systemBackground)     // Adapts automatically
ダークモードのテスト
// Preview both modes
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .preferredColorScheme(.light)

        ContentView()
            .preferredColorScheme(.dark)
    }
}
ダークモードのガイドライン

推奨事項:

  • ✅ セマンティックカラーを使用します
  • ✅ コントラストを上げる設定を有効にしてテストします
  • ✅ 透明度を下げる設定を有効にしてテストします
  • ✅ どちらのモードでも十分なコントラストを確保します

禁止事項:

  • ❌ 純粋な黒(#000000)を使用しないでください。systemBackground を使用します
  • ❌ 色を自動的に反転しないでください
  • ❌ ユーザーの設定を決めつけないでください

SF Symbols

Apple のアイコンシステム(3000 以上のシンボル)です。

// Basic symbol
Image(systemName: "heart")

// Colored symbol
Image(systemName: "heart.fill")
    .foregroundColor(.red)

// Sized symbol
Image(systemName: "heart")
    .imageScale(.large)

// Font-based sizing
Image(systemName: "heart")
    .font(.title)

// Multicolor symbols
Image(systemName: "person.crop.circle.fill.badge.checkmark")
    .symbolRenderingMode(.multicolor)

// Hierarchical rendering
Image(systemName: "heart.fill")
    .symbolRenderingMode(.hierarchical)
    .foregroundColor(.red)
SF Symbols のガイドライン
  • 利用できる場合はシステムシンボルを使用します
  • 視覚的なウェイトの一貫性を保ちます
  • セマンティックな意味を表す場合はマルチカラーを使用します
  • 用途に合ったサイズにします

アプリアイコン

アイコンのサイズ
iOS:
- 1024x1024 (App Store)
- 180x180 (iPhone @3x)
- 120x120 (iPhone @2x)
- 167x167 (iPad Pro)
- 152x152 (iPad @2x)

watchOS:
- 1024x1024 (App Store)
- 196x196 (49mm)
- 216x216 (45mm)
アイコンデザインのガイドライン

推奨事項:

  • ✅ シンプルで認識しやすい形状を使用します
  • ✅ アイコンの領域全体を使います
  • ✅ モックアップだけでなく、デバイス上でもテストします
  • ✅ 一貫したビジュアルスタイルを使用します

禁止事項:

  • ❌ テキストを含めないでください(非常に小さく表示されます)
  • ❌ 写真を使用しないでください
  • ❌ Apple のハードウェアを模倣しないでください
  • ❌ 半透明を使用しないでください

アニメーションとモーション

標準アニメーション
// Spring animation (natural, bouncy)
withAnimation(.spring()) {
    offset = 100
}

// Linear animation
withAnimation(.linear(duration: 0.3)) {
    opacity = 0
}

// Ease in/out
withAnimation(.easeInOut(duration: 0.3)) {
    scale = 1.2
}
ジェスチャー駆動
@State private var offset = CGSize.zero

var body: some View {
    Circle()
        .offset(offset)
        .gesture(
            DragGesture()
                .onChanged { value in
                    offset = value.translation
                }
                .onEnded { _ in
                    withAnimation(.spring()) {
                        offset = .zero
                    }
                }
        )
}
モーションに関するガイドライン
  • アニメーションは 0.3 秒未満にします
  • インタラクティブな要素にはスプリングアニメーションを使用します
  • 「モーションを減らす」設定を尊重します
  • すべての操作に視覚的なフィードバックを提供します

ベストプラクティス

ナビゲーション
  • 階層型 - 詳細画面への移動には NavigationStack を使用します
  • フラット型 - 同列の画面への移動には TabView を使用します
  • コンテンツ主導型 - メディアアプリで使用します
フィードバック
  • 視覚 - タップ時にハイライトします
  • 触覚 - UIImpactFeedbackGenerator を使用します
  • 音声 - システムサウンドは控えめに使用します
読み込み状態
struct LoadingView: View {
    var body: some View {
        VStack {
            ProgressView()
                .scaleEffect(1.5)
            Text("Loading...")
                .font(.caption)
                .foregroundColor(.secondary)
                .padding(.top)
        }
    }
}
エラー状態
struct ErrorView: View {
    let message: String
    let retry: () -> Void

    var body: some View {
        VStack(spacing: 16) {
            Image(systemName: "exclamationmark.triangle")
                .font(.system(size: 48))
                .foregroundColor(.orange)

            Text("Something went wrong")
                .font(.headline)

            Text(message)
                .font(.subheadline)
                .foregroundColor(.secondary)
                .multilineTextAlignment(.center)

            Button("Try Again") {
                retry()
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}
空の状態
struct EmptyStateView: View {
    var body: some View {
        VStack(spacing: 16) {
            Image(systemName: "tray")
                .font(.system(size: 64))
                .foregroundColor(.secondary)

            Text("No Items")
                .font(.title2)

            Text("Your items will appear here")
                .font(.subheadline)
                .foregroundColor(.secondary)

            Button("Add Item") {
                // Action
            }
            .buttonStyle(.borderedProminent)
        }
    }
}

プラットフォームに関する考慮事項

iPhone
  • さまざまなサイズ(SE、Pro、Pro Max)に対応するデザインにします
  • 縦向きと横向きに対応します
  • ノッチ/Dynamic Island にはセーフエリアを使用します
  • 片手での操作を考慮します
iPad
  • マルチタスク(Split View、Slide Over)に対応します
  • ナビゲーションにはサイドバーを使用します
  • 大きな画面に合わせて調整します(単に拡大するだけにしません)
  • キーボードショートカットを考慮します
  • 外部ディスプレイに対応します
Apple Watch
  • ひと目で把握できる情報を表示します
  • 大きなタッチターゲット(>44pt)にします
  • 必要な操作を最小限にします
  • スクロールには Digital Crown を使用します
  • 常時表示ディスプレイに対応します

リソース


「デザインとは、見た目や使い心地だけではありません。デザインとは、どのように機能するかです。」 - Steve Jobs

コメント