7.9 KiB
7.9 KiB
Dark Mode色使用ガイドライン
🎯 目的
このガイドラインは、Dark Mode対応を自動化し、手動の条件分岐を完全に排除することで、以下を実現します:
- ✅ すべての画面で一貫したDark Mode体験
- ✅ 新機能追加時にDark Mode問題が発生しない
- ✅ メンテナンスコストの削減
- ✅ 個性のある配色(白だらけにならない)
❌ 絶対にやってはいけないこと
1. ハードコード色の使用
// ❌ NG: ハードコード
Icon(LucideIcons.star, color: Colors.blue)
Icon(LucideIcons.star, color: Color(0xFF376495))
Container(color: Colors.white)
2. 手動Dark Mode条件分岐
// ❌ 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の直接使用
// ❌ NG: primaryColorは内部でDark/Light切り替えが必要
Icon(LucideIcons.star, color: Theme.of(context).primaryColor)
✅ 正しい使い方
Material 3 ColorSchemeを使う
Flutter Material 3は、Dark/Light両モードに自動対応するセマンティックカラーを提供しています。
基本パターン
// ✅ 正しい: 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) |
自動調整 | 自動調整 | チップ、バッジ背景 |
🔧 実装例
✅ アイコン
// セクションヘッダー(アクセントカラー)
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)
✅ テキスト
// 見出し(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,
),
)
✅ 背景色
// カード背景
Container(
color: Theme.of(context).colorScheme.surface,
child: ...,
)
// 半透明背景(ブランドカラー)
Container(
color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1),
child: ...,
)
✅ ボタン
// プライマリボタン
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('アクション'),
)
🚨 特殊ケース(例外)
エラー・警告・成功(セマンティックカラー)
一部の色は意味が固定されているため、ハードコードが許可されます:
// ✅ OK: エラーは常に赤
Icon(LucideIcons.alertTriangle, color: Colors.red)
// ✅ OK: 成功は常に緑
Icon(LucideIcons.checkCircle, color: Colors.green)
// ✅ OK: 警告は常にオレンジ
Icon(LucideIcons.info, color: Colors.orange)
ただし、可能な限り colorScheme.error を使用してください:
// ✅ より良い: Material 3のエラーカラー
Icon(LucideIcons.alertTriangle, color: Theme.of(context).colorScheme.error)
🔍 既存コードの修正方法
パターン1: primaryColor → colorScheme.primary
// Before ❌
Icon(LucideIcons.star, color: Theme.of(context).primaryColor)
// After ✅
Icon(LucideIcons.star, color: Theme.of(context).colorScheme.primary)
パターン2: 手動条件分岐 → colorScheme.onSurface
// 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
// 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: ポシマイブルー#376495secondary: 濃いオレンジ#FF6F00surface: 白#FFFFFFonPrimary: 白(自動計算)onSecondary: 白(自動計算)onSurface: 黒(自動計算)
Dark Mode
primary: 明るい青#8AB4F8secondary: 温かいオレンジ#FFB74Dsurface: ダークグレー#1E1E1EonPrimary: 黒(自動計算)onSecondary: 黒(自動計算)onSurface: 白(自動計算)
✅ チェックリスト
新しい画面/ウィジェットを作成する際は、以下を確認してください:
- ハードコード色を使っていない(
Colors.blue,Color(0xFF...)など) brightness == Brightness.darkの条件分岐を使っていないTheme.of(context).primaryColorの代わりにcolorScheme.primaryを使用- アイコンは
colorScheme.secondaryまたはcolorScheme.onSurface - テキストは
textTheme.xxxを使用 - 背景は
colorScheme.surfaceを使用
🔗 参考資料
最終更新: 2026-01-21 作成者: Claude (Antigravity AI)