274 lines
7.9 KiB
Markdown
274 lines
7.9 KiB
Markdown
|
|
# 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)
|