# Dark Mode色使用ガイドライン ## 🎯 目的 このガイドラインは、Dark Mode対応を**自動化**し、手動の条件分岐を**完全に排除**することで、以下を実現します: 1. ✅ すべての画面で一貫したDark Mode体験 2. ✅ 新機能追加時にDark Mode問題が発生しない 3. ✅ メンテナンスコストの削減 4. ✅ 個性のある配色(白だらけにならない) --- ## ❌ 絶対にやってはいけないこと ### 1. ハードコード色の使用 ```dart // ❌ NG: ハードコード Icon(LucideIcons.star, color: Colors.blue) Icon(LucideIcons.star, color: Color(0xFF376495)) Container(color: Colors.white) ``` ### 2. 手動Dark Mode条件分岐 ```dart // ❌ NG: 手動条件分岐 final isDark = Theme.of(context).brightness == Brightness.dark; color: isDark ? Colors.white : Colors.black // ❌ NG: Theme.of(context).brightnessの直接使用 color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[400] : null ``` ### 3. Theme.of(context).primaryColorの直接使用 ```dart // ❌ NG: primaryColorは内部でDark/Light切り替えが必要 Icon(LucideIcons.star, color: Theme.of(context).primaryColor) ``` --- ## ✅ 正しい使い方 ### Material 3 ColorSchemeを使う Flutter Material 3は、Dark/Light両モードに自動対応する**セマンティックカラー**を提供しています。 #### 基本パターン ```dart // ✅ 正しい: ColorSchemeを使う Theme.of(context).colorScheme.primary // メインブランドカラー Theme.of(context).colorScheme.secondary // アクセントカラー Theme.of(context).colorScheme.onSurface // 一般的なアイコン/テキスト Theme.of(context).colorScheme.surface // 背景色 Theme.of(context).colorScheme.error // エラー色 ``` --- ## 📘 用途別カラー選択ガイド | 用途 | 使用するカラー | Dark Mode | Light Mode | 例 | |------|---------------|-----------|------------|-----| | **見出し・セクションヘッダー** | `colorScheme.secondary` | オレンジ `#FFB74D` | 濃いオレンジ `#FF6F00` | ガイド画面「レベルと称号」 | | **重要なボタン** | `colorScheme.primary` | 明るい青 `#8AB4F8` | ポシマイブルー `#376495` | FAB、プライマリボタン | | **一般的なアイコン** | `colorScheme.onSurface` | 白/グレー(自動) | 黒/グレー(自動) | リスト項目のアイコン | | **一般的なテキスト** | `textTheme.bodyMedium` | 白(自動) | 黒(自動) | 本文テキスト | | **強調テキスト** | `colorScheme.primary` | 明るい青 | ポシマイブルー | リンク、強調部分 | | **エラーメッセージ** | `colorScheme.error` | 赤(自動調整) | 赤(自動調整) | エラー表示 | | **背景色** | `colorScheme.surface` | ダークグレー `#1E1E1E` | 白 | カード、ダイアログ | | **半透明背景** | `colorScheme.primary.withValues(alpha: 0.1)` | 自動調整 | 自動調整 | チップ、バッジ背景 | --- ## 🔧 実装例 ### ✅ アイコン ```dart // セクションヘッダー(アクセントカラー) Icon(LucideIcons.trophy, color: Theme.of(context).colorScheme.secondary) // 一般的なアイコン Icon(LucideIcons.user, color: Theme.of(context).colorScheme.onSurface) // 重要なアイコン Icon(LucideIcons.sparkles, color: Theme.of(context).colorScheme.primary) ``` ### ✅ テキスト ```dart // 見出し(Theme準拠) Text( '見出し', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ) // 強調テキスト(プライマリカラー) Text( '重要', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: Theme.of(context).colorScheme.primary, ), ) // アクセント見出し(セカンダリカラー) Text( 'セクション名', style: Theme.of(context).textTheme.titleMedium?.copyWith( color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.bold, ), ) ``` ### ✅ 背景色 ```dart // カード背景 Container( color: Theme.of(context).colorScheme.surface, child: ..., ) // 半透明背景(ブランドカラー) Container( color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1), child: ..., ) ``` ### ✅ ボタン ```dart // プライマリボタン ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primary, foregroundColor: Theme.of(context).colorScheme.onPrimary, ), child: Text('保存'), ) // セカンダリボタン(アクセント) ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.secondary, foregroundColor: Theme.of(context).colorScheme.onSecondary, ), child: Text('アクション'), ) ``` --- ## 🚨 特殊ケース(例外) ### エラー・警告・成功(セマンティックカラー) 一部の色は**意味が固定**されているため、ハードコードが許可されます: ```dart // ✅ OK: エラーは常に赤 Icon(LucideIcons.alertTriangle, color: Colors.red) // ✅ OK: 成功は常に緑 Icon(LucideIcons.checkCircle, color: Colors.green) // ✅ OK: 警告は常にオレンジ Icon(LucideIcons.info, color: Colors.orange) ``` ただし、可能な限り `colorScheme.error` を使用してください: ```dart // ✅ より良い: Material 3のエラーカラー Icon(LucideIcons.alertTriangle, color: Theme.of(context).colorScheme.error) ``` --- ## 🔍 既存コードの修正方法 ### パターン1: primaryColor → colorScheme.primary ```dart // Before ❌ Icon(LucideIcons.star, color: Theme.of(context).primaryColor) // After ✅ Icon(LucideIcons.star, color: Theme.of(context).colorScheme.primary) ``` ### パターン2: 手動条件分岐 → colorScheme.onSurface ```dart // Before ❌ final isDark = Theme.of(context).brightness == Brightness.dark; Icon(LucideIcons.user, color: isDark ? Colors.grey[400] : null) // After ✅ Icon(LucideIcons.user, color: Theme.of(context).colorScheme.onSurface) ``` ### パターン3: セクションヘッダー → colorScheme.secondary ```dart // Before ❌ Icon(LucideIcons.trophy, color: Theme.of(context).primaryColor) Text('見出し', style: TextStyle(color: Theme.of(context).primaryColor)) // After ✅(アクセントカラーで目立たせる) Icon(LucideIcons.trophy, color: Theme.of(context).colorScheme.secondary) Text('見出し', style: Theme.of(context).textTheme.titleMedium?.copyWith( color: Theme.of(context).colorScheme.secondary, )) ``` --- ## 📦 ColorScheme定義(app_theme.dart) 現在のカラースキーム: ### Light Mode - `primary`: ポシマイブルー `#376495` - `secondary`: 濃いオレンジ `#FF6F00` - `surface`: 白 `#FFFFFF` - `onPrimary`: 白(自動計算) - `onSecondary`: 白(自動計算) - `onSurface`: 黒(自動計算) ### Dark Mode - `primary`: 明るい青 `#8AB4F8` - `secondary`: 温かいオレンジ `#FFB74D` - `surface`: ダークグレー `#1E1E1E` - `onPrimary`: 黒(自動計算) - `onSecondary`: 黒(自動計算) - `onSurface`: 白(自動計算) --- ## ✅ チェックリスト 新しい画面/ウィジェットを作成する際は、以下を確認してください: - [ ] ハードコード色を使っていない(`Colors.blue`, `Color(0xFF...)` など) - [ ] `brightness == Brightness.dark` の条件分岐を使っていない - [ ] `Theme.of(context).primaryColor` の代わりに `colorScheme.primary` を使用 - [ ] アイコンは `colorScheme.secondary` または `colorScheme.onSurface` - [ ] テキストは `textTheme.xxx` を使用 - [ ] 背景は `colorScheme.surface` を使用 --- ## 🔗 参考資料 - [Material 3 Color System](https://m3.material.io/styles/color/the-color-system/overview) - [Flutter ColorScheme API](https://api.flutter.dev/flutter/material/ColorScheme-class.html) --- **最終更新:** 2026-01-21 **作成者:** Claude (Antigravity AI)