テーマシステムとは?設計方法・実装手順・ダークモード対応まで徹底解説
Webサイトやアプリケーションの規模が大きくなると、ページごとに色、文字サイズ、余白、枠線、影などが個別に指定され、画面全体の統一感が失われやすくなります。新しいブランドカラーを導入するだけでも、数十から数百のファイルを修正しなければならず、変更漏れや表示崩れが発生することも少なくありません。こうした問題を防ぐために活用される仕組みが、テーマシステムです。
テーマシステムは、単に背景を白から黒へ切り替える機能ではありません。色、文字、余白、角丸、影、動きなどの視覚的な規則を一元化し、複数の画面や製品で再利用できる状態にする設計基盤です。適切に設計すれば、ダークモード、ブランド別表示、季節キャンペーン、利用者ごとの表示設定なども、既存画面を大幅に作り直すことなく実現できます。
本記事では、テーマシステムの意味や導入背景だけでなく、設計対象となる要素、デザイントークンの構造、CSS変数やJavaScriptを使った実装方法、アクセシビリティ、品質管理、段階的な導入手順まで詳しく解説します。
1. テーマシステムとは
テーマシステムを正しく導入するには、最初に「何をテーマとして管理するのか」を明確にする必要があります。色だけを切り替える簡易的な仕組みと、製品全体の視覚表現を制御する仕組みでは、必要な設計範囲が大きく異なるためです。
1.1 テーマシステムとは何か
テーマシステムとは、画面上で使用する色、文字、余白、枠線、角丸、影などの視覚的な値を、一定の規則に基づいて管理し、目的に応じて切り替えられるようにする仕組みです。各部品が具体的な色コードを直接参照するのではなく、「主背景」「通常文字」「強調色」といった役割を通じて値を参照します。
役割を基準に値を管理すると、画面の意味を保ったまま外観だけを変更できます。たとえば、明るいテーマでは主背景を白、通常文字を濃い灰色に設定し、暗いテーマでは主背景を黒に近い色、通常文字を明るい灰色に変更できます。部品側の実装を変更しなくても、参照先の値を差し替えるだけで表示を切り替えられます。
1.2 テーマが管理する対象
テーマシステムで管理する対象は、背景色や文字色だけではありません。見出しの文字サイズ、本文の行間、部品間の余白、ボタンの高さ、入力欄の枠線、カードの影、アニメーションの時間なども、統一的に扱うことができます。対象範囲を広げるほど、製品全体の一貫性を高めやすくなります。
一方で、すべての値を最初からテーマ化すると、設計や移行の負担が大きくなります。導入初期は、利用頻度と変更頻度が高い色、文字、余白から管理を始める方法が現実的です。その後、角丸、影、動きなどを段階的に追加すると、既存開発を止めずに適用範囲を広げられます。
| 管理対象 | 主な内容 | 切り替え例 |
|---|---|---|
| 色 | 背景、文字、枠線、状態色 | 明るい表示、暗い表示 |
| 文字 | 書体、サイズ、太さ、行間 | ブランド別の書体 |
| 余白 | 内側余白、外側余白、間隔 | 高密度表示、標準表示 |
| 形状 | 角丸、枠線幅 | 柔らかい印象、直線的な印象 |
| 効果 | 影、透明度、ぼかし | 平面的な表示、立体的な表示 |
| 動き | 時間、加速方法 | 通常表示、動きを抑えた表示 |
1.3 テーマ切り替えが成立する仕組み
テーマ切り替えは、部品が参照する名前を固定し、その名前に割り当てる値だけを変更することで成立します。ボタンの背景色を青色として直接指定するのではなく、「主要操作の背景色」という名前を参照させます。テーマごとに、この名前へ異なる色を割り当てます。
この構造では、部品は現在どのテーマが選ばれているかを知る必要がありません。部品は役割名だけを参照し、テーマ管理側が実際の値を提供します。責任範囲を分離できるため、テーマ追加時の修正箇所が減り、既存部品への影響も抑えられます。
実装例
:root {
--color-surface-primary: #ffffff;
--color-text-primary: #1f2937;
--color-action-primary: #2563eb;
}
[data-theme="dark"] {
--color-surface-primary: #111827;
--color-text-primary: #f3f4f6;
--color-action-primary: #60a5fa;
}
.button {
color: var(--color-surface-primary);
background-color: var(--color-action-primary);
}
1.4 テーマと利用者設定の関係
テーマは、運営者が一方的に指定するだけでなく、利用者が選択できる表示設定として提供される場合があります。明るい表示、暗い表示、端末設定に合わせる表示などを用意すれば、利用環境や好みに応じた画面を選択できます。長時間利用される管理画面や業務アプリでは、特に重要な機能です。
利用者が選択したテーマは、再訪問時にも維持されることが望まれます。ブラウザ内の保存領域、利用者アカウントの設定、端末の表示設定などを組み合わせ、読み込み直後から正しいテーマを表示できるようにします。保存方法が不十分だと、最初に明るい画面が一瞬表示されてから暗い画面へ変わるちらつきが発生します。
1.5 テーマシステムが必要になる規模
小規模な紹介ページでは、色や余白を直接記述しても管理できる場合があります。しかし、画面数、部品数、担当者数、ブランド数が増えるにつれて、個別指定の修正コストは急速に増加します。複数人が異なる基準で値を追加すると、似た色や余白が大量に生まれ、統一が難しくなります。
テーマシステムが必要かどうかは、ページ数だけで判断すべきではありません。定期的なブランド更新、複数サービスへの展開、ダークモードの提供、外部企業向けの外観変更などが予定されている場合は、小規模な段階でも早めに導入する価値があります。
2. テーマシステムが求められる背景
テーマシステムの需要が高まっている理由には、製品の大規模化だけでなく、利用環境やブランド展開の多様化があります。見た目を一度決めて固定する設計では、継続的な変更に対応しにくくなっています。
2.1 複数画面で発生する表示の不統一
ページごとに色や余白を直接指定すると、同じ役割を持つ部品でも異なる見た目になりやすくなります。ある画面の主要ボタンは濃い青、別の画面では少し明るい青というように、小さな差が積み重なります。利用者にとっては、どの操作が重要なのか判断しにくい画面になります。
テーマシステムでは、役割ごとに利用可能な値を限定できます。主要操作、補助操作、警告、成功などの表示規則を共通化すれば、新しい画面を追加しても既存の規則に沿って設計できます。結果として、設計者や開発者が変わっても一貫した表示を維持しやすくなります。
2.2 ブランド変更に伴う修正負担
企業やサービスでは、ブランドカラー、書体、ロゴ周辺の余白、角丸の方針などが変更されることがあります。値が各画面へ直接記述されている場合、対象箇所を検索し、個別に修正しなければなりません。似た色コードや例外的な指定が存在すると、変更漏れも発生します。
テーマシステムによってブランド値が集約されていれば、中心となる定義を変更することで、多数の画面へ反映できます。ただし、単純に一つの色を置換するだけでは、文字とのコントラストや状態色との関係が崩れる可能性があります。そのため、役割単位で影響を確認できる構造が必要です。
| 変更方法 | 修正範囲 | 変更漏れ | 確認負担 |
|---|---|---|---|
| 各画面を個別修正 | 広い | 発生しやすい | 大きい |
| 共通部品のみ修正 | 中程度 | 例外箇所に残りやすい | 中程度 |
| テーマ定義を修正 | 限定的 | 抑えやすい | 影響確認に集中できる |
2.3 ダークモードへの需要
暗い環境で明るい画面を使用すると、画面のまぶしさを強く感じる場合があります。そのため、端末や基本ソフトの表示設定に合わせて、暗い配色へ切り替えられるWebサイトやアプリが増えています。ダークモードは、単純な色反転ではなく、読みやすさや情報の優先度を保つ再設計が必要です。
テーマシステムを使えば、部品ごとに暗い色を個別指定するのではなく、背景、文字、枠線、状態色の関係をまとめて定義できます。新しい部品も共通の役割名を参照するため、ダークモードへの対応漏れを減らせます。将来の配色追加にも対応しやすくなります。
2.4 複数ブランドへの展開
一つの製品基盤を複数企業や複数サービスへ提供する場合、機能は共通でも、色、ロゴ、書体、角丸などを変更する必要があります。ブランドごとに別の画面を作成すると、機能修正をすべての製品へ反映しなければならず、保守コストが増加します。
機能と外観を分離し、ブランドごとのテーマを読み込む構造にすれば、共通の部品を維持したまま表示だけを変更できます。ブランド追加時には、必要なテーマ値と画像資産を用意するだけで展開できるため、新規導入までの期間も短縮できます。
2.5 開発チームの分業拡大
設計者、フロントエンド開発者、外部制作会社など、複数の関係者が同じ製品に関わると、口頭や資料だけで表示規則を共有することが難しくなります。担当者ごとに解釈が異なれば、同じ名称の色や余白でも別の値が使われます。
テーマシステムは、表示規則を実際に利用できるデータとして共有する役割を持ちます。設計資料と実装値を連携させれば、仕様書を確認しながら手入力する作業を減らせます。人による判断を完全になくすものではありませんが、判断が必要な範囲を限定できます。
3. 色を中心としたテーマ設計
色はテーマシステムの中で最も変化が目立つ要素です。しかし、色コードを一覧化するだけでは、実用的なテーマ設計にはなりません。色が担う役割と、背景や文字との関係を定義する必要があります。
3.1 色コードではなく役割で命名する
色の名前を「青500」「灰色100」のような見た目だけで定義すると、実際にどこで使用すべきか判断しにくくなります。また、ブランド変更によって主要色が青から緑へ変わった場合、「青」という名前と実際の色が一致しなくなる問題も生じます。
部品が参照する色は、「主要背景」「通常文字」「補助文字」「主要操作」「危険操作」など、画面上の役割で命名します。色そのものを管理する基礎値と、役割を示す値を分ければ、色体系を保ちながらテーマ変更に対応できます。
実装例
:root {
--palette-blue-600: #2563eb;
--palette-red-600: #dc2626;
--palette-gray-900: #111827;
--color-text-primary: var(--palette-gray-900);
--color-action-primary: var(--palette-blue-600);
--color-action-danger: var(--palette-red-600);
}
3.2 背景色を階層で設計する
画面内には、ページ全体の背景、カードの背景、浮き上がったメニューの背景、入力欄の背景など、複数の背景階層があります。すべてを同じ色にすると情報のまとまりが見えにくくなり、逆に差を大きくしすぎると画面が分断された印象になります。
背景色は「最背面」「主要面」「副次面」「浮上面」などの階層に分けて設計します。特にダークモードでは、影が見えにくくなるため、背景の明度差によって高さや重なりを表現する必要があります。背景階層を先に決めると、カードやダイアログの設計も安定します。
| 背景の役割 | 使用場所 | 設計上の注意 |
|---|---|---|
| 最背面 | ページ全体 | 長時間見ても負担が少ない明度にする |
| 主要面 | 本文、カード | 最背面との差を小さく保つ |
| 副次面 | 入力欄、補助領域 | 操作可能性を示せる差を設ける |
| 浮上面 | メニュー、ダイアログ | 周囲との境界を明確にする |
3.3 文字色の優先度を分ける
すべての文字を同じ濃さで表示すると、見出し、本文、補足情報の優先度が伝わりにくくなります。一方、補助文字を薄くしすぎると、読みづらさやアクセシビリティ上の問題が発生します。文字色は装飾ではなく、情報構造を示す要素として設計する必要があります。
通常文字、補助文字、無効状態、リンク、反転文字など、用途ごとに役割を分けます。その際、背景ごとに十分なコントラストが確保されているかを確認します。特に小さい文字では、見た目の美しさよりも読みやすさを優先することが重要です。
3.4 状態色を体系化する
成功、注意、危険、情報などの状態色は、通知、入力検証、ラベル、グラフなど多くの場所で使われます。画面ごとに異なる色を使うと、同じ赤色がエラーと選択状態の両方を示すなど、意味が衝突する可能性があります。
状態色には、背景、文字、枠線、強調部分の組み合わせを用意します。一色だけを定義するのではなく、薄い背景と濃い文字を対にして管理すると、通知枠や状態ラベルを安全に再利用できます。明るいテーマと暗いテーマの双方で意味が維持されることも確認します。
実装例
:root {
--color-success-surface: #ecfdf5;
--color-success-text: #047857;
--color-success-border: #6ee7b7;
--color-danger-surface: #fef2f2;
--color-danger-text: #b91c1c;
--color-danger-border: #fca5a5;
}
3.5 色の例外を増やさない
キャンペーンや特別な画面を制作するとき、既存のテーマにない色を一時的に追加したくなることがあります。しかし、例外色を無制限に追加すると、テーマを切り替えても一部だけ元の色が残り、画面全体の一貫性が失われます。
例外が必要な場合は、値を直接記述するのではなく、利用目的と有効期間を明確にした専用の役割名を追加します。期間終了後に削除する予定も管理し、恒久的なテーマ値と混在させないことが重要です。例外の承認手順を設けると、色体系の肥大化を抑えられます。
4. 文字表現をテーマ化する方法
文字は情報の読みやすさとブランド印象の両方に影響します。書体だけでなく、サイズ、太さ、行間、文字間隔まで含めて設計することで、画面全体の情報階層を安定させられます。
4.1 書体の役割を分ける
本文、見出し、数値、コード表示では、求められる読みやすさが異なります。すべての場所で同じ書体を使う方法もありますが、ブランド表現や数値の判別性を高めるために、用途別の書体を設定する場合があります。
テーマでは、「本文用」「見出し用」「等幅表示用」などの役割名を用意します。ブランドごとに書体を変更するときも、部品側は役割名を参照し続けます。代替書体まで含めた指定を共通化することで、利用者の環境による表示差も抑えられます。
実装例
:root {
--font-family-body:
"Noto Sans JP",
"Hiragino Kaku Gothic ProN",
sans-serif;
--font-family-heading:
"Noto Sans JP",
sans-serif;
--font-family-code:
"SFMono-Regular",
Consolas,
monospace;
}
4.2 文字サイズを段階化する
画面ごとに任意の文字サイズを指定すると、14ピクセル、15ピクセル、16ピクセルなどの近い値が増え、情報階層が不明瞭になります。わずかな違いでは視覚的な意味が伝わらないため、必要以上に多くのサイズを用意すべきではありません。
本文、小さな補足、見出し、小見出し、画面タイトルなど、用途を基準に段階を定義します。端末幅によってサイズを変える場合も、段階同士の関係が崩れないように設計します。文字サイズだけでなく、太さや余白を組み合わせることで階層を表現できます。
| 役割 | 使用例 | 設計方針 |
|---|---|---|
| 補足文字 | 注釈、更新日時 | 読みやすさを保てる最小値にする |
| 本文 | 説明、入力内容 | 長文を読み続けやすい大きさにする |
| 小見出し | カード見出し | 本文との差を明確にする |
| 大見出し | ページ内の主要区分 | 余白と組み合わせて階層を示す |
| 画面タイトル | ページの主題 | 過度に大きくせず内容を優先する |
4.3 行間を用途別に設定する
行間が狭すぎると長文を追いにくくなり、広すぎると段落としてのまとまりが弱くなります。見出しと本文では適切な行間が異なるため、文字サイズだけを統一しても読みやすい画面にはなりません。
テーマでは、本文用、短文用、見出し用などの行間を定義します。日本語は文字の密度が高いため、欧文を中心にした値をそのまま使用すると窮屈に見えることがあります。実際の日本語文章を使い、複数の端末幅で確認することが重要です。
4.4 文字の太さを制限する
利用可能な太さを増やしすぎると、設計者や開発者が場面ごとに異なる値を選び、視覚的な規則が崩れます。また、読み込む書体ファイルが増えることで、表示速度へ影響する可能性もあります。
通常、強調、見出しなど、必要な太さを少数に限定します。擬似的に太く表示すると文字の輪郭が不自然になる場合があるため、実際に使用する太さの書体ファイルを用意します。ブランド別テーマで書体を変更する場合は、同じ太さでも見え方が異なる点に注意が必要です。
4.5 端末幅に応じた文字設計
パソコン向けの大きな見出しをスマートフォンへそのまま表示すると、改行が増えて画面上部を占有します。反対に、小さい端末を基準にした文字サイズを大画面へ固定すると、情報の重要度が弱く見える場合があります。
文字サイズを連続的に変化させる方法や、画面幅ごとに段階を切り替える方法を利用します。ただし、端末ごとに完全に異なる文字体系を作ると管理が複雑になります。共通の役割を維持しながら、必要な範囲だけ調整する設計が適しています。
実装例
:root {
--font-size-page-title: clamp(1.75rem, 1.25rem + 2vw, 3rem);
--font-size-section-title: clamp(1.375rem, 1.1rem + 1vw, 2rem);
--font-size-body: 1rem;
--line-height-body: 1.8;
}
5. 余白・角丸・影の設計
テーマシステムでは、色と文字だけでなく、画面の密度や立体感を決める値も管理します。余白、角丸、影を共通化すると、別々の部品でも同じ製品らしい印象を作れます。
5.1 余白を一定の規則で定義する
余白を任意の値で指定すると、11ピクセル、13ピクセル、15ピクセルのような細かな差が増えます。こうした差は利用者に意味を伝えにくい一方で、実装や修正を複雑にします。一定の基準値から段階を作る方法が有効です。
小さい間隔、標準間隔、大きい間隔など、用途に応じた値を用意します。値の名称には、具体的な場所ではなく大きさや役割を使用します。同じ余白値をカード、フォーム、一覧などで共有すれば、異なる画面でも一定のリズムが生まれます。
| 余白の役割 | 主な用途 | 設計上の意図 |
|---|---|---|
| 極小 | アイコンと文字の間 | 関連性を強く示す |
| 小 | 入力欄内部、短い間隔 | 部品内部のまとまりを作る |
| 標準 | 部品同士の間 | 通常の情報区切りに使う |
| 大 | 節同士の間 | 内容の区分を明確にする |
| 特大 | 画面上部、主要領域 | 強い区切りを作る |
5.2 部品内部と部品外部を分ける
ボタン内部の余白と、ボタン同士の間隔では意味が異なります。両方を同じ名前で管理すると、部品の大きさを変更した際に画面全体の配置まで変化する可能性があります。内部と外部の余白は、目的を分けて設計する必要があります。
内部余白は、操作領域の大きさや文字との距離を決めます。外部余白は、情報同士の関係や区切りを表します。テーマ値を分けておくことで、高密度表示では外部余白だけを縮小し、操作しやすい部品サイズは維持するといった調整が可能になります。
5.3 角丸でブランド印象を制御する
角丸は小さな要素に見えますが、製品全体の印象に強く影響します。大きな角丸は親しみやすく柔らかい印象を作り、角丸を抑えると堅実で業務的な印象を作りやすくなります。
部品ごとに任意の角丸を設定するのではなく、小、中、大、完全な円形などの段階を用意します。ブランド別テーマでは、この段階に割り当てる値を変えることで、部品構造を変えずに印象を調整できます。ただし、入力欄やボタンの形状が大きく変わる場合は、内部余白との関係も確認します。
5.4 影を高さの表現として使う
影は装飾のためだけでなく、画面上の重なりや高さを示すために使われます。カード、固定メニュー、選択肢一覧、ダイアログなど、それぞれの高さに応じて影を分けると、操作対象の位置関係を理解しやすくなります。
影の値を部品名で定義すると、同じ高さにある別の部品で再利用しにくくなります。「低い浮上」「中程度の浮上」「最前面」のように高さを基準に管理します。ダークモードでは黒い影が見えにくいため、枠線や背景差と組み合わせる必要があります。
実装例
:root {
--radius-small: 0.375rem;
--radius-medium: 0.75rem;
--radius-large: 1.25rem;
--shadow-low: 0 1px 2px rgb(0 0 0 / 8%);
--shadow-middle: 0 8px 24px rgb(0 0 0 / 14%);
--shadow-high: 0 20px 48px rgb(0 0 0 / 20%);
}
5.5 表示密度をテーマとして扱う
業務用の一覧画面では、一度に多くの情報を確認したい利用者がいます。一方、一般利用者向けの画面では、十分な余白と大きな操作領域が求められます。同じ機能でも、用途によって適切な表示密度が異なります。
標準表示と高密度表示をテーマの一種として管理すれば、行の高さ、部品間隔、入力欄の高さなどをまとめて切り替えられます。ただし、操作領域を小さくしすぎると、タッチ操作やアクセシビリティへ悪影響が出ます。変更可能な値と最低限維持する値を分けて設計します。
6. デザイントークンによる値の管理
テーマシステムを拡張しやすい状態にするには、表示に使う値を構造化して管理する必要があります。その中心となるのがデザイントークンです。
6.1 デザイントークンとは
デザイントークンとは、色、文字、余白、角丸などの設計値に名前を付け、再利用できるデータとして管理する方法です。単なる変数ではなく、設計上の意図を名前と階層で表現する点に特徴があります。
デザイントークンを利用すると、設計資料、Web実装、スマートフォン向け実装などで共通の意味を持つ値を共有できます。出力形式は異なっても、元となる定義を一つに保つことで、複数環境の表示差を抑えられます。
6.2 基礎値と役割値を分ける
色体系を管理するときは、色そのものを表す基礎値と、画面上の用途を表す役割値を分けます。基礎値には青や灰色の段階を登録し、役割値には主要操作、通常文字、危険状態などを登録します。
部品が基礎値を直接参照すると、ブランド変更やダークモード対応の際に部品側の修正が必要になります。部品は役割値を参照し、役割値がテーマごとに異なる基礎値へ接続される構造にします。これにより、色体系と利用目的を分離できます。
| 階層 | 内容 | 参照する対象 |
|---|---|---|
| 基礎値 | 色や寸法そのもの | 原則として役割値から参照 |
| 役割値 | 画面上の意味 | 部品から参照 |
| 部品値 | 特定部品での用途 | 複雑な部品のみ使用 |
6.3 部品専用値を増やしすぎない
特定の部品にしか使わない値を定義すると、細かな調整はしやすくなります。しかし、ボタン背景、カード背景、通知背景など、部品ごとの値を無制限に増やすと、テーマ変更時に確認すべき項目が膨大になります。
最初は共通の役割値で表現し、共通値では要件を満たせない場合だけ部品専用値を追加します。追加時には、なぜ共通値を利用できないのかを記録します。利用目的が重複する値を定期的に統合すると、テーマ構造の肥大化を防げます。
6.4 データ形式を統一する
デザイントークンは、JSONやJavaScriptの設定ファイルなどで管理できます。重要なのは、値、種類、説明、参照関係を一定の形式で記述することです。担当者ごとに形式が異なると、自動変換や検証が難しくなります。
値だけでなく、廃止予定、利用範囲、説明などの情報を持たせると、長期運用がしやすくなります。ただし、最初から複雑な形式を導入すると更新が滞る可能性があります。実際に必要な情報から始め、運用上の課題に合わせて項目を増やします。
実装例
{
"color": {
"surface": {
"primary": {
"value": "{palette.neutral.0}",
"description": "ページおよび主要領域の背景色"
}
},
"text": {
"primary": {
"value": "{palette.neutral.900}",
"description": "通常の本文に使用する文字色"
}
}
}
}
6.5 トークン名を長期運用できる形にする
トークン名に現在の色や特定画面の名称を入れると、将来の変更で意味が合わなくなる可能性があります。「青いボタン」ではなく「主要操作背景」、「会員登録ページ背景」ではなく「認証画面背景」のように、役割や範囲を表す名前が適しています。
一方で、抽象的すぎる名前も利用者を迷わせます。「第一色」「第二色」だけでは、どの場面に使うか判断できません。名称だけで利用目的がある程度推測でき、説明文を読めば判断を確定できる状態を目指します。
7. CSS変数を使ったテーマ実装
Webサイトでテーマシステムを実装する方法として、CSS変数は扱いやすく、幅広い構成に適用できます。実行時に値を切り替えられるため、ページを再構築せずにテーマ変更を反映できます。
7.1 ルート要素へ共通値を定義する
標準テーマの値は、文書全体から参照できるルート要素へ定義します。部品のCSSでは、色コードや固定値を直接指定せず、共通の変数を参照します。これにより、変更箇所をテーマ定義へ集約できます。
すべての変数を一つの巨大なファイルへ記述すると、管理が難しくなります。色、文字、余白、影などの分類ごとにファイルを分け、最終的に読み込む構成が適しています。出力時に一つへまとめれば、通信回数を増やさずに管理性を保てます。
実装例
:root {
--color-surface-primary: #ffffff;
--color-surface-secondary: #f8fafc;
--color-text-primary: #0f172a;
--color-text-secondary: #475569;
--space-small: 0.5rem;
--space-medium: 1rem;
--space-large: 2rem;
}
7.2 属性でテーマを切り替える
文書の上位要素へテーマを示す属性を付け、その属性に応じて変数を上書きする方法が一般的です。上位要素の値が子要素へ継承されるため、各部品へテーマ名を渡す必要がありません。
属性名は、テーマ以外の用途と衝突しない明確な名前にします。テーマ数が増える場合も、同じ属性へ異なる値を設定することで対応できます。部品内でテーマごとの条件分岐を増やさず、変数の上書きへ集約することが重要です。
実装例
[data-theme="light"] {
--color-surface-primary: #ffffff;
--color-text-primary: #0f172a;
}
[data-theme="dark"] {
--color-surface-primary: #0f172a;
--color-text-primary: #f8fafc;
}
body {
color: var(--color-text-primary);
background: var(--color-surface-primary);
}
7.3 変数の代替値を設定する
CSS変数が未定義の場合、対象の宣言が無効になることがあります。テーマの追加途中や一部画面への段階導入では、必要な値が欠ける可能性があります。そのため、重要な表示には代替値を設定すると安全です。
ただし、すべての変数に代替値を設定すると、定義漏れに気付きにくくなる問題があります。利用者の操作を妨げる重大な箇所には代替値を設け、開発時には検証処理によって不足を検出する方法が適しています。
実装例
.card {
color: var(--color-text-primary, #111827);
background-color: var(--color-surface-primary, #ffffff);
border-color: var(--color-border-default, #d1d5db);
}
7.4 部品内で固定色を使わない
テーマ対応した画面でも、アイコン、読み込み表示、グラフ、通知などに固定色が残ることがあります。一部の固定色は明るいテーマで問題がなくても、暗いテーマでは背景と同化したり、強く目立ちすぎたりします。
固定色を完全に禁止するのではなく、許可される用途を定義します。写真やブランドロゴなど、テーマに依存しない資産は固定表示が必要です。一方、操作や状態を示す色は、原則としてテーマ変数を参照させます。
7.5 部分的なテーマ適用に対応する
埋め込み部品やプレビュー領域など、ページの一部だけ異なるテーマで表示したい場合があります。CSS変数は子要素へ継承されるため、対象領域の上位要素で変数を上書きすれば、部分的なテーマを実現できます。
ただし、ポップアップや選択肢一覧が文書直下へ移動して描画される構成では、親領域のテーマを継承できない場合があります。描画先へテーマ属性を引き継ぐか、部品に必要な値を明示的に渡す仕組みを用意します。
実装例
<section data-theme="dark" class="preview-area">
<article class="card">
暗いテーマで表示されるプレビュー
</article>
</section>
8. JavaScriptとTypeScriptによる制御
CSS変数だけでも外観は変更できますが、利用者の選択保存、端末設定の検出、複数テーマの管理にはJavaScriptやTypeScriptが必要です。
8.1 テーマ名を一か所で管理する
複数の画面でテーマ名を文字列として直接使用すると、表記揺れや入力ミスが発生します。TypeScriptでは、利用可能なテーマ名を型として定義し、想定外の値が渡されないようにできます。
テーマ追加時には、型、設定データ、選択画面など複数箇所の更新が必要になる場合があります。テーマ一覧を一つの設定から生成できる構造にすると、追加漏れを減らせます。
実装例
export const themes = ["light", "dark", "brand"] as const;
export type ThemeName = (typeof themes)[number];
export function isThemeName(value: string): value is ThemeName {
return themes.includes(value as ThemeName);
}
8.2 文書へテーマ属性を設定する
選択されたテーマは、文書の最上位要素へ属性として設定します。テーマ変更のたびに各部品の状態を更新するのではなく、属性変更によってCSS変数を一括で切り替えます。
この方法では、表示に関する処理をCSSへ任せられるため、JavaScript側の処理を小さく保てます。属性を変更した直後に画面全体へ反映され、部品ごとの再描画も最小限に抑えられます。
実装例
export function applyTheme(theme: ThemeName): void {
document.documentElement.dataset.theme = theme;
}
8.3 利用者の選択を保存する
利用者が明示的に選んだテーマは、ページを閉じた後も維持する必要があります。ブラウザ内の保存領域を使う方法は簡単ですが、別端末には同期されません。利用者アカウントへ保存すれば、複数端末で設定を共有できます。
保存値は、読み込み時に必ず検証します。過去に存在していたテーマ名や、不正な値が残っている可能性があるためです。利用可能なテーマでなければ、端末設定または標準テーマへ戻します。
実装例
const STORAGE_KEY = "preferred-theme";
export function saveTheme(theme: ThemeName): void {
localStorage.setItem(STORAGE_KEY, theme);
}
export function loadTheme(): ThemeName | null {
const value = localStorage.getItem(STORAGE_KEY);
return value && isThemeName(value) ? value : null;
}
8.4 端末の表示設定を検出する
利用者がテーマを明示的に選んでいない場合、端末の明暗設定に合わせると自然な表示になります。ブラウザでは、配色設定に関する問い合わせを利用して、暗い表示が希望されているか確認できます。
端末設定は利用中に変更される場合があります。「端末設定に合わせる」を選択した利用者には、変更を検出して画面へ反映します。一方、明るいテーマや暗いテーマを明示的に選んだ利用者には、端末設定の変更を上書きしないようにします。
実装例
const darkQuery = window.matchMedia("(prefers-color-scheme: dark)");
export function getSystemTheme(): ThemeName {
return darkQuery.matches ? "dark" : "light";
}
darkQuery.addEventListener("change", () => {
const savedTheme = loadTheme();
if (!savedTheme) {
applyTheme(getSystemTheme());
}
});
8.5 初期表示のちらつきを防ぐ
JavaScriptの読み込み後にテーマを設定すると、最初に標準テーマが表示され、その直後に選択テーマへ切り替わることがあります。暗いテーマを選んでいる利用者に白い画面が一瞬表示されると、強い違和感につながります。
主要な画面が描画される前に、保存値と端末設定を確認してテーマ属性を設定します。小さな初期化処理を文書上部で実行し、その後に本体のCSSやアプリケーションを読み込む構成が有効です。
実装例
<script>
(() => {
const saved = localStorage.getItem("preferred-theme");
const dark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const theme = saved || (dark ? "dark" : "light");
document.documentElement.dataset.theme = theme;
})();
</script>
9. Reactでテーマシステムを構築する方法
Reactでは、テーマ状態を部品へ共有する仕組みと、CSS変数による表示制御を組み合わせると、保守しやすい構成を作れます。
9.1 テーマ状態を共有する
テーマ切り替えボタン、設定画面、利用者メニューなど、複数の部品から現在のテーマを参照する場合があります。個別に状態を持たせると同期が難しくなるため、共通の提供機構を利用します。
ただし、色や余白の値そのものをすべてReactの状態として渡す必要はありません。Reactでは現在のテーマ名と変更処理を共有し、実際の表示値はCSS変数から取得する構成が軽量です。
実装例
import {
createContext,
useContext,
useMemo,
useState,
type ReactNode
} from "react";
type ThemeName = "light" | "dark" | "system";
type ThemeContextValue = {
theme: ThemeName;
setTheme: (theme: ThemeName) => void;
};
const ThemeContext = createContext<ThemeContextValue | null>(null);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<ThemeName>("system");
const value = useMemo(
() => ({ theme, setTheme }),
[theme]
);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useThemeはThemeProvider内で使用してください");
}
return context;
}
9.2 テーマ変更を文書へ反映する
React内のテーマ状態が変わったら、文書のテーマ属性も更新します。「端末設定に合わせる」が選ばれている場合は、端末の現在設定から実際に適用するテーマを決定します。
状態と文書属性が別々に管理されるため、更新処理を一つの場所へ集約することが重要です。複数の部品から直接文書属性を書き換えると、保存値や端末設定との不整合が起こりやすくなります。
実装例
import { useEffect } from "react";
function useApplyTheme(theme: "light" | "dark" | "system") {
useEffect(() => {
const query = window.matchMedia("(prefers-color-scheme: dark)");
const updateTheme = () => {
const applied =
theme === "system"
? query.matches
? "dark"
: "light"
: theme;
document.documentElement.dataset.theme = applied;
};
updateTheme();
query.addEventListener("change", updateTheme);
return () => {
query.removeEventListener("change", updateTheme);
};
}, [theme]);
}
9.3 テーマ選択部品を作る
テーマ選択画面では、現在の選択状態が明確に伝わる必要があります。色の見本だけで選択させると、色覚特性や画面環境によって判別しにくくなるため、文字ラベルや選択状態の印も併用します。
選択肢は、明るい表示、暗い表示、端末設定に合わせる表示など、利用者が結果を理解できる名称にします。内部のテーマ名をそのまま表示せず、利用者向けの説明へ変換します。
実装例
const themeOptions = [
{ value: "light", label: "明るい表示" },
{ value: "dark", label: "暗い表示" },
{ value: "system", label: "端末設定に合わせる" }
] as const;
export function ThemeSelector() {
const { theme, setTheme } = useTheme();
return (
<fieldset>
<legend>画面の表示</legend>
{themeOptions.map((option) => (
<label key={option.value}>
<input
type="radio"
name="theme"
value={option.value}
checked={theme === option.value}
onChange={() => setTheme(option.value)}
/>
{option.label}
</label>
))}
</fieldset>
);
}
9.4 サーバー側描画とテーマを両立する
サーバー側でHTMLを生成する構成では、ブラウザ内の保存値をサーバーが直接確認できない場合があります。サーバーが明るいテーマを出力し、ブラウザ側で暗いテーマへ変更すると、ちらつきや描画内容の不一致が起こる可能性があります。
利用者設定をCookieへ保存し、サーバー側でも参照できるようにする方法があります。端末設定のみを利用する場合はサーバー側で確定できないため、描画前の小さな処理で属性を設定します。どの情報をサーバーと共有するかを事前に決めることが重要です。
9.5 部品ライブラリへテーマを適用する
外部の部品ライブラリを使用する場合、独自のテーマ値とライブラリ側の設定を対応付ける必要があります。ライブラリの既定色をそのまま利用すると、自社画面の一部だけ異なる印象になる場合があります。
可能であれば、自社の役割値をライブラリのテーマ設定へ割り当てます。直接上書きするCSSを大量に追加する方法は、ライブラリ更新時に壊れやすいため注意が必要です。公式に提供されている外観変更方法を優先します。
10. ダークモードを設計する方法
ダークモードは、明るいテーマの色を機械的に反転させるだけでは成立しません。情報の優先度、読みやすさ、画像、影、状態色まで含めた調整が必要です。
10.1 背景を完全な黒に固定しない
完全な黒色は高いコントラストを作れますが、広い面積で使用すると文字との境界が強くなり、長時間の閲覧で負担を感じる場合があります。また、有機発光式の画面では利点がある一方、すべての端末で同じ見え方になるわけではありません。
濃い灰色やわずかに色味を持つ暗色を主要背景として使い、必要に応じて完全な黒を限定的に利用します。製品のブランド印象や表示内容に合わせて、複数の端末で確認することが重要です。
10.2 白文字の明るさを調整する
暗い背景へ完全な白文字を表示すると、コントラストが強すぎて文字がにじんだように見えることがあります。本文では少し明度を下げた白を使い、重要な見出しや選択状態のみ明るくする方法が有効です。
補助文字を暗くしすぎると読めなくなるため、背景とのコントラストを測定しながら調整します。明るいテーマと同じ明度差を機械的に再現するのではなく、暗い背景上での実際の見え方を確認します。
| 文字の役割 | 明るさの方針 | 注意点 |
|---|---|---|
| 主要文字 | 高い明度 | 完全な白を広範囲で使いすぎない |
| 補助文字 | 中程度の明度 | 小さい文字では薄くしすぎない |
| 無効状態 | 低い明度 | 操作不能であることを別の方法でも示す |
| 反転文字 | 背景に応じて調整 | 強調色上での可読性を確認する |
10.3 強調色の彩度を抑える
明るいテーマで使用している鮮やかな色を暗い背景へそのまま置くと、強く発光しているように見える場合があります。特に青、緑、赤などの高彩度色は、広い面積で使用すると視覚的な負担になります。
ダークモードでは、同じ色相を保ちながら彩度や明度を調整します。主要ボタン、リンク、状態表示など、利用面積や重要度に応じて値を分けることも有効です。ブランドカラーを完全に同じ値で維持するのではなく、ブランドらしさを保てる範囲で最適化します。
10.4 影以外の方法で高さを示す
暗い背景では黒い影が見えにくく、カードやダイアログの高さを表現できない場合があります。影を濃くするだけでは、境界が不自然に見えることもあります。
背景の明度差、細い枠線、周囲のぼかしなどを組み合わせます。最前面のダイアログでは、背後へ半透明の覆いを表示することで、影だけに依存せず重なりを伝えられます。
実装例
[data-theme="dark"] {
--color-surface-primary: #111827;
--color-surface-raised: #1f2937;
--color-border-default: #374151;
--shadow-middle:
0 0 0 1px rgb(255 255 255 / 6%),
0 12px 32px rgb(0 0 0 / 45%);
}
10.5 画像と図表も確認する
白い背景を前提に作られた画像は、ダークモード上で白い長方形として目立つ場合があります。透明なロゴや細い線の図も、暗い背景では見えなくなる可能性があります。
テーマ別の画像を用意する、画像周囲に専用背景を設ける、図表の色をテーマ値から生成するなどの対応が必要です。利用者が投稿する画像まで完全に制御することは難しいため、画像領域の背景や枠線で安定した表示を確保します。
11. ブランド別テーマの構築
複数ブランドで共通の製品基盤を使用する場合、テーマシステムは開発効率とブランド再現性の両方に影響します。
11.1 共通部分とブランド部分を分離する
すべての値をブランドごとに複製すると、修正内容を各テーマへ反映する必要があります。反対に、すべてを共通化すると、ブランドごとの違いを十分に表現できません。
余白の基準や状態色など、製品全体で共通にすべき値と、主要色、書体、角丸など、ブランドごとに変更する値を分けます。ブランドテーマは共通テーマを土台として、必要な値だけを上書きする構造が適しています。
11.2 ブランドカラーを役割へ割り当てる
ブランドカラーを登録しただけでは、ボタン、リンク、選択状態、装飾など、どこで使うかが決まりません。利用範囲を定めずに使うと、画面全体がブランドカラーで埋まり、情報の優先度が失われます。
主要操作、リンク、選択状態など、ブランドカラーを割り当てる役割を明確にします。ブランドカラー上の文字色や、薄い背景で使用する派生色も合わせて定義します。
| ブランド要素 | 適用候補 | 確認事項 |
|---|---|---|
| 主要色 | 主要操作、選択状態 | 文字とのコントラスト |
| 補助色 | ラベル、装飾 | 主要色との優先度 |
| 書体 | 見出し、本文 | 読み込み速度と日本語対応 |
| 角丸 | ボタン、カード | 部品サイズとの相性 |
| ロゴ | 上部領域、認証画面 | 明暗背景への対応 |
11.3 ロゴと画像資産を管理する
ブランド別テーマでは、色だけでなくロゴ、背景画像、模様、アイコンなどの資産も切り替える場合があります。画像の参照先が各部品へ直接記述されていると、ブランド追加時の修正箇所が増えます。
テーマ設定に画像資産の参照先を含め、上位の設定から部品へ提供します。ロゴには、明るい背景用、暗い背景用、横長、正方形など複数形式が必要になる場合があります。必要形式を共通仕様として定めます。
11.4 ブランドごとの例外を制御する
特定ブランドだけボタンの高さや画面構造を変更したいという要望が生じることがあります。しかし、テーマは外観の変更を中心とする仕組みであり、機能や情報構造まで無制限に変更すると共通基盤を維持できません。
テーマで変更できる範囲を契約や仕様として明確にします。色、書体、角丸は変更可能、主要な画面配置は共通といった境界を設けます。境界を超える要望は、個別機能として費用と保守方法を別に判断します。
11.5 新しいブランドを追加しやすくする
ブランド追加のたびに開発者が多数のファイルを修正する構成では、テーマシステムの利点が十分に得られません。設定ファイルと画像資産を追加し、検証を通過すれば利用できる状態が理想です。
必須値の不足、色のコントラスト、画像形式、名称の重複などを自動検証します。確認用の全体表示ページを用意すると、主要部品を一画面で確認でき、ブランド担当者との調整も進めやすくなります。
12. アクセシビリティを考慮したテーマ設計
テーマ切り替えによって見た目が変わっても、情報の意味や操作可能性は維持されなければなりません。アクセシビリティは、テーマ完成後に追加確認するのではなく、設計段階から組み込む必要があります。
12.1 文字と背景のコントラストを確保する
文字色と背景色の差が小さいと、視力や利用環境によって文章を読みにくくなります。補助文字、入力欄の説明、無効状態などは薄い色が選ばれやすく、特に注意が必要です。
テーマごとに、主要な文字と背景の組み合わせを自動検査します。通常状態だけでなく、押下時、選択時、無効時、エラー時も確認します。色コード単体ではなく、実際に組み合わせる役割同士で検査することが重要です。
| 対象 | 確認する組み合わせ | 見落としやすい点 |
|---|---|---|
| 本文 | 通常文字と主要背景 | 補助文字だけ基準を下回る |
| ボタン | ボタン文字と操作背景 | 押下時の色で読めなくなる |
| 入力欄 | 入力文字と入力背景 | 説明文や仮表示が薄すぎる |
| 通知 | 状態文字と状態背景 | 薄い背景色で差が不足する |
| リンク | リンク文字と背景 | 訪問済みの色だけ読みにくい |
12.2 色だけで状態を伝えない
入力エラーを赤色だけで示すと、色の違いを認識しにくい利用者へ情報が伝わりません。成功、警告、選択状態なども、色だけに依存すべきではありません。
文字による説明、アイコン、枠線の形、下線、太さなどを組み合わせます。テーマを変更して色の見え方が変わっても、状態の意味が維持されます。特にグラフでは、色に加えて模様やラベルを使用します。
12.3 焦点表示をテーマ化する
キーボード操作では、現在どの要素が選択されているかを示す焦点表示が重要です。テーマ変更によって焦点枠が背景へ溶け込むと、操作位置を見失います。
明るい背景、暗い背景、強調色の背景など、複数の場所で見える焦点色を設計します。必要に応じて二重線や背景との間隔を利用し、周囲の色に依存しにくい表示を作ります。
実装例
:focus-visible {
outline: 3px solid var(--color-focus-ring);
outline-offset: 3px;
}
[data-theme="light"] {
--color-focus-ring: #1d4ed8;
}
[data-theme="dark"] {
--color-focus-ring: #93c5fd;
}
12.4 動きを抑える設定へ対応する
テーマシステムでは、色や形だけでなく、動きの設定も利用者環境に合わせて変更できます。大きな移動や点滅は、一部の利用者へ不快感や負担を与える可能性があります。
端末側で動きを抑える設定が有効な場合、画面遷移、拡大縮小、背景移動などを停止または短縮します。ただし、処理中であることを示す表示まで完全に消すと、状態が分からなくなります。必要な情報を維持しながら動きだけを抑えます。
実装例
:root {
--motion-duration-fast: 120ms;
--motion-duration-normal: 240ms;
}
@media (prefers-reduced-motion: reduce) {
:root {
--motion-duration-fast: 1ms;
--motion-duration-normal: 1ms;
}
}
12.5 高コントラスト表示を検討する
明るいテーマと暗いテーマだけでは、すべての利用者の視認性要件を満たせない場合があります。文字や境界をより明確にした高コントラスト表示を追加することで、利用しやすさを高められます。
高コントラストテーマでは、装飾的な影や微妙な背景差に依存せず、明確な枠線と文字差を使用します。既存テーマの色を単純に強くするのではなく、情報階層と操作状態が明確になるように再設計します。
13. テーマシステムと関連手法の違い
テーマシステムは、デザインシステム、デザイントークン、CSS変数、外観設定などと混同されることがあります。役割の違いを理解すると、必要な仕組みを適切に選択できます。
13.1 テーマシステムとデザインシステムの違い
テーマシステムは、主に外観を構成する値の管理と切り替えを担当します。デザインシステムは、それに加えて設計原則、部品仕様、文章表現、利用方法、制作手順など、製品設計全体の規則を扱います。
テーマシステムはデザインシステムの一部として組み込まれることがありますが、両者は同じものではありません。テーマだけを導入しても、部品の使い分けや画面設計の原則までは統一されません。
| 比較項目 | テーマシステム | デザインシステム |
|---|---|---|
| 主な目的 | 外観値の管理と切り替え | 製品設計全体の統一 |
| 対象 | 色、文字、余白、影など | 原則、部品、文章、手順を含む |
| 切り替え | 複数の外観を切り替える | 必須ではない |
| 利用範囲 | 実装寄り | 設計から実装、運用まで |
13.2 テーマシステムとデザイントークンの違い
デザイントークンは、色や余白などの値を名前付きデータとして管理する方法です。テーマシステムは、そのデータを組み合わせ、条件に応じて外観を切り替える仕組みです。
デザイントークンがなくてもテーマを作ることはできますが、値が増えるほど管理が難しくなります。反対に、デザイントークンを導入しても、切り替え処理や利用者設定がなければテーマシステムにはなりません。
| 比較項目 | テーマシステム | デザイントークン |
|---|---|---|
| 主な役割 | 外観の適用と切り替え | 設計値の構造化 |
| 状態管理 | 必要になる場合がある | 原則として扱わない |
| 利用者操作 | テーマ選択として提供可能 | 直接操作しない |
| 関係 | トークンを利用して構築できる | テーマの材料になる |
13.3 テーマシステムとCSS変数の違い
CSS変数は、スタイル内で値を再利用し、実行時に上書きできる技術です。テーマシステムは、命名規則、テーマデータ、切り替え方法、保存方法、検証、運用まで含む設計全体を指します。
CSS変数を使用しただけでは、役割名が統一されていなかったり、固定色が多数残っていたりする可能性があります。技術を導入するだけでなく、どの値をどの責任範囲で管理するかを決める必要があります。
| 比較項目 | テーマシステム | CSS変数 |
|---|---|---|
| 種類 | 設計と運用の仕組み | Web標準の技術 |
| 対象範囲 | 値、切り替え、保存、検証 | CSS内の値参照 |
| 他環境への展開 | 形式変換により可能 | Web表示が中心 |
| 単独利用 | 複数技術を組み合わせる | 単独で値管理に利用できる |
13.4 テーマシステムとダークモードの違い
ダークモードは、暗い背景を中心にした一つの表示形式です。テーマシステムは、ダークモードを含む複数の表示形式を管理し、切り替えるための基盤です。
ダークモードだけを個別に追加すると、将来ブランドテーマや高コントラストテーマを追加する際に仕組みを作り直す可能性があります。複数テーマへの拡張を想定し、共通の切り替え基盤として構築する方法が適しています。
| 比較項目 | テーマシステム | ダークモード |
|---|---|---|
| 主な意味 | 複数外観を管理する仕組み | 暗い配色の表示形式 |
| テーマ数 | 複数を扱える | 一つのテーマ |
| 対象 | 色以外の値も含む | 主に明暗と関連表示 |
| 拡張性 | ブランドや密度にも展開可能 | 単独実装では限定的 |
13.5 テーマシステムとスタイルガイドの違い
スタイルガイドは、使用する色、文字、ロゴ、部品などを文書として説明するものです。テーマシステムは、その規則を実際の画面へ適用できるデータと処理として実装します。
スタイルガイドだけでは、開発者が値を手入力するため、記述ミスや更新漏れが発生する可能性があります。テーマシステムと連携させることで、文書上の規則と実際の表示値を近づけられます。
| 比較項目 | テーマシステム | スタイルガイド |
|---|---|---|
| 提供形式 | 実行可能な設定やコード | 文書、見本、説明 |
| 自動反映 | 可能 | 原則として不可能 |
| 主な利用者 | 開発者、設計者、利用者 | 設計者、制作担当者 |
| 更新時の影響 | 画面へ反映できる | 実装側の修正が別途必要 |
14. テーマシステムの運用と品質管理
テーマシステムは、一度実装して終わる仕組みではありません。画面やブランドの追加に合わせて値が増えるため、更新手順と品質確認を継続する必要があります。
14.1 追加と変更の承認手順を決める
誰でも自由にテーマ値を追加できる状態では、似た値や用途不明の名前が増えます。一方、承認手順が重すぎると、開発者が共通値を使わずに固定値を記述する原因になります。
追加理由、利用箇所、既存値で代替できない理由を簡潔に記録し、設計と開発の担当者が確認できる流れを作ります。小さな変更と大きな変更で承認範囲を分けると、速度と品質を両立しやすくなります。
14.2 変更による影響範囲を確認する
一つのテーマ値が多数の部品から参照されている場合、値の変更が予想外の画面へ影響する可能性があります。名前だけを見て変更すると、別の用途で使われていたことに気付けません。
利用箇所を検索できる仕組みや、主要部品を一覧表示する確認ページを用意します。大きな変更では、変更前後の画面画像を比較し、意図しない差分がないか確認します。
| 確認方法 | 確認できる内容 | 適した場面 |
|---|---|---|
| 利用箇所検索 | 参照しているファイルや部品 | 値を削除、改名するとき |
| 部品一覧表示 | 主要部品への影響 | 色や角丸を変更するとき |
| 画像差分 | 見た目の変化 | 広範囲な更新 |
| 自動検査 | 不足値、形式、コントラスト | すべての変更 |
14.3 廃止予定の値を管理する
不要になった値をすぐ削除すると、古い画面や外部部品が動作しなくなる可能性があります。しかし、廃止値を永遠に残すと、新旧の値が混在し、どちらを使うべきか分からなくなります。
廃止予定であること、代替値、削除予定時期を記録します。開発時に警告を表示できる仕組みがあれば、段階的な移行を促せます。参照箇所がなくなったことを確認してから削除します。
14.4 自動検査を導入する
人による確認だけでは、必須値の不足、誤った色形式、重複した名前などを見落とす可能性があります。テーマデータを読み込み、規則に違反していないか自動的に検査します。
ブランドテーマでは、共通テーマに存在する必須の役割値がすべて定義されているか確認します。色のコントラストや参照先の循環も検査対象にできます。変更提出時に検査を実行すると、不具合が本番環境へ入る前に発見できます。
実装例
type Theme = Record<string, string>;
const requiredKeys = [
"color.surface.primary",
"color.text.primary",
"color.action.primary",
"color.border.default"
];
export function validateTheme(theme: Theme): string[] {
return requiredKeys.filter((key) => !theme[key]);
}
14.5 更新履歴を共有する
テーマ値の変更は、画面全体の印象や操作性へ影響します。変更理由が共有されていないと、別の担当者が以前の値へ戻したり、似た値を再追加したりする可能性があります。
追加、変更、廃止を更新履歴へ記録し、影響する部品や移行方法を示します。すべての細かな修正を長文で残す必要はありませんが、利用者や開発者の対応が必要な変更は明確に伝えます。
15. テーマシステムの導入手順
既存製品へテーマシステムを導入する際は、すべての画面を一度に変更しようとすると負担が大きくなります。現状把握、構造設計、試験導入、段階移行の順に進めることが重要です。
15.1 現在使われている値を調査する
最初に、画面内で使用されている色、文字サイズ、余白、角丸、影を収集します。同じ目的で複数の値が使われている箇所や、固定色が集中している部品を把握します。
収集した値をそのままテーマへ登録するのではなく、利用目的ごとに分類します。似た値を統合し、例外が必要な箇所を確認します。現状の混乱をそのまま新しい仕組みへ移さないことが重要です。
| 調査対象 | 確認内容 | 導入時の判断 |
|---|---|---|
| 色 | 重複、近似色、固定色 | 統合可能な色を選ぶ |
| 文字 | サイズ、太さ、行間 | 情報階層へ再分類する |
| 余白 | 任意値、例外値 | 共通段階へ置き換える |
| 角丸 | 部品ごとの差 | ブランド方針に合わせる |
| 影 | 用途と強さ | 高さの段階へ分類する |
15.2 最小限の役割値を定義する
調査後は、主要背景、通常文字、主要操作、標準枠線など、利用頻度の高い役割値から定義します。最初から数百の値を作ると、名称や階層の議論だけで導入が止まりやすくなります。
主要画面を再現できる最小構成を作り、不足した値を実際の移行作業から発見します。追加理由が実際の利用箇所に基づくため、不要な値を増やしにくくなります。
15.3 代表的な画面で試験導入する
ログイン画面だけのような単純な画面では、複雑な課題を発見できません。フォーム、一覧、通知、ダイアログ、状態表示など、複数種類の部品を含む代表画面を選びます。
試験導入では、明るいテーマと暗いテーマの両方を作成し、役割名が適切か確認します。特定部品で例外が大量に必要になる場合は、値の階層や部品設計を見直します。
15.4 既存画面を段階的に移行する
すべての固定値を一度に置き換えると、変更範囲が広くなり、不具合の原因を特定しにくくなります。画面単位、部品単位、機能単位など、確認可能な範囲へ分けて移行します。
新しく作る画面ではテーマ値の使用を必須とし、既存画面は優先度に応じて置き換えます。新旧の指定が長期間混在しないよう、期限と進捗を管理します。固定値の追加を検出する規則も有効です。
15.5 導入効果を継続的に測定する
テーマシステムの効果は、ダークモードを公開できたかだけでは判断できません。変更に必要な時間、固定値の数、表示不具合、ブランド追加にかかった期間などを測定します。
導入後も値の数が増え続ける場合、追加規則や名称が分かりにくい可能性があります。開発者や設計者への聞き取りも行い、利用しにくい部分を改善します。テーマシステム自体を継続的に更新することで、長期的な効果を維持できます。
| 評価項目 | 確認方法 | 期待される変化 |
|---|---|---|
| 外観変更時間 | 更新前後の作業時間を比較 | 修正時間が短くなる |
| 固定値の数 | コード内を自動検査 | 固定指定が減少する |
| 表示不具合 | テーマ関連の不具合件数 | 変更漏れが減少する |
| ブランド追加期間 | 導入開始から公開までを測定 | 展開期間が短くなる |
| 値の重複 | 類似値と役割名を確認 | 重複が抑制される |
おわりに
テーマシステムは、配色を変更するためだけの機能ではありません。色、文字、余白、角丸、影、動きなどを役割ごとに管理し、製品全体へ一貫して適用するための設計基盤です。適切なテーマシステムがあれば、ダークモード、ブランド別表示、高密度表示、高コントラスト表示などを、共通部品を維持しながら展開できます。
導入時に重要なのは、現在使われている値をそのまま変数へ置き換えることではありません。見た目を表す基礎値と、画面上の意味を表す役割値を分け、部品が具体的な色や寸法へ依存しない構造を作る必要があります。さらに、アクセシビリティ、自動検査、変更履歴、廃止手順まで設計することで、長期運用に耐えられる仕組みになります。
既存製品へ導入する場合は、主要な色と文字から始め、代表画面で検証しながら段階的に適用範囲を広げる方法が現実的です。最初から完璧な構造を目指すのではなく、実際の利用状況を確認しながら名称、階層、検証規則を改善していくことが、使いやすいテーマシステムを構築する近道です。
EN
JP
KR