マガジン

ゲームのダークモード対応:背景と光の表現を切り替える

遊びをつくる

執筆にClaudeを使用しています。

明暗の異なる色見本と拡大鏡で、ゲーム画面のコントラストを表すイラスト。
記事のテーマをもとに制作したAI生成イラスト。

ダークモード対応は「画面を暗くすればいい」と思われがちですが、ゲームにとってはそれほど単純ではありません。UIアプリと違って、ゲームには背景・キャラクター・エフェクト・テキスト・光源演出など、明度と色が複雑に絡み合う要素が重なっています。単純に背景を黒くするだけでは、もともと暗色で設計されたキャラクターが背景に溶け込んだり、グロー(発光)エフェクトが飛びすぎたりします。 この記事では、ブラウザゲームのダークモード対応を「背景の明度切り替え」「光・エフェクトの再設計」「テキストとUIの可読性確保」という三つの軸に分けて、実装の判断基準と手順を整理します。OS・ブラウザのダークモード設定を検知してゲームに反映する方法から、Canvas描画とCSS両方での対応まで扱います。

この記事の目次
  1. ダークモードを検知する:OSの設定を読み取る
  2. 背景と地色をモードごとに設計する
  3. 光・エフェクトの再設計が最も難しい
  4. テキストとUIパーツの可読性を確保する
  5. 実装の優先順位と段階的な対応
  6. 次の行動
  7. 参考資料

ダークモードを検知する:OSの設定を読み取る

ブラウザには prefers-color-scheme というメディアクエリが用意されており、OSのダークモード設定を取得できます。CSSとJavaScriptの両方から参照できるのが特徴です。

CSSでの使い方は次の通りです。

css
@media (prefers-color-scheme: dark) {
  body {
    background-color: #111;
    color: #eee;
  }
}

JavaScriptから取得する場合は window.matchMedia を使います。

js
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

さらに、実行中にユーザーがOSの設定を変えたときにも追従したい場合は、addEventListener でイベントを監視します。

js
window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', (e) => {
    applyTheme(e.matches ? 'dark' : 'light');
  });

ただし、ゲームの場合はOSの設定に自動追従するだけでなく、「ゲーム内にライト/ダーク切り替えボタンを置く」選択肢も重要です。ゲーム中にいきなり画面のトーンが変わるとプレイ体験が壊れるため、多くのゲームはOS連動をデフォルトにしつつ、設定画面から手動で固定できるようにしています。

背景と地色をモードごとに設計する

ダークモードの背景は「黒(#000)」にしない方が多くの場面でうまくいきます。純黒は最も明度が低く、キャラクターや背景オブジェクトの輪郭が潰れやすいためです。実務では #0d0d0d〜#1a1a2e 程度の「ほぼ黒だが少し色味がある」値がよく使われます。

色の設計には「背景」「表面」「境界」の三層を分けて考えると管理しやすくなります。

  • 背景(最奥)、ライトモード例:#f5f5f5、ダークモード例:#111827
  • 表面(パネル・カード)、ライトモード例:#ffffff、ダークモード例:#1f2937
  • 境界・区切り、ライトモード例:#d1d5db、ダークモード例:#374151

CSS変数(カスタムプロパティ)を使うと、切り替え時の記述が最小限になります。

css
:root {
  --bg-base: #f5f5f5;
  --bg-surface: #ffffff;
  --text-primary: #111827;
}

[data-theme="dark"] {
  --bg-base: #111827;
  --bg-surface: #1f2937;
  --text-primary: #f9fafb;
}

data-theme 属性を document.documentElement に付け外しするだけで全体を切り替えられます。

Canvasを使ったゲームでは、CSSが直接Canvasの描画内容に効きません。描画ループの中で背景色を変数で管理し、テーマに応じて fillStyle を切り替える形になります。

js
const theme = { bg: '#111827', surface: '#1f2937' };

function drawBackground(ctx) {
  ctx.fillStyle = theme.bg;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
}

光・エフェクトの再設計が最も難しい

ダークモード対応で最も見落とされやすいのが、グロー・シャドウ・パーティクルなどの光表現です。ライトモードで「ほのかに光る」程度に調整したエフェクトが、ダークモードでは強すぎて目に刺さることがあります。逆に、ライトモードで白背景に白い発光エフェクトを乗せていた場合、ダークモードでは突然真っ白なブラシが浮かび上がるように見えることもあります。

グローエフェクトの強度を分ける

CSSの text-shadow や box-shadow でグローを作っている場合は、テーマ変数に強度を持たせます。

css
:root {
  --glow-strength: 0 0 8px rgba(99, 102, 241, 0.3);
}
[data-theme="dark"] {
  --glow-strength: 0 0 14px rgba(99, 102, 241, 0.7);
}

Canvasで shadowBlur を使う場合も同様に、テーマに応じて数値を変えます。ダークモードでは shadowBlur を少し強め、ライトモードでは弱めるか省略するのが基本の方向性です。

重ね合わせモード(blend mode)の挙動を確認する

Canvas の globalCompositeOperation で 'screen' や 'lighter' を使っている場合、背景が暗いほど加算効果が強く出ます。ライトモードで自然だったパーティクルが、ダークモードで非常に強く光って見えることがあります。ダークモードではパーティクルの alpha 値を下げるか、'source-over' に切り替えて別の演出で補う判断が必要です。

影(シャドウ)の方向と意味

ライトモードでは「光が上から当たる」前提でドロップシャドウを付けることが多いですが、ダークモードでは影を完全に消すかごく淡くする方が自然です。暗い背景に濃い影を付けると不自然なフラットさが生まれます。代わりに border や outline で境界を表現する方が読み取りやすくなります。

テキストとUIパーツの可読性を確保する

コントラスト比はアクセシビリティの観点でも重要で、WCAG(ウェブコンテンツアクセシビリティガイドライン)ではテキストと背景のコントラスト比を通常サイズで4.5:1以上、大きなテキストで3:1以上と定めています。ダークモードではライトモードとは違う組み合わせになるため、両方のモードでそれぞれ確認が必要です。

ブラウザの開発者ツールや、ChromeのLighthouseにはコントラスト比のチェック機能が含まれています。設計段階でパレットを確定させるには「Colour Contrast Analyser」などのツールが役立ちます(公式サイトで最新版を確認してください)。

ゲームに出てくるボタンやスコア表示は、ライトモードでは「白背景に黒文字」が読みやすかったとしても、ダークモードではそのまま使うと浮いて見えます。--text-primary などの変数で文字色をテーマごとに定義し、ハードコードした色値をできるだけコードから排除しておくと、後から修正するコストが下がります。

アイコンや画像素材については、PNG・SVGで用意する際にライト用とダーク用を別ファイルにしておく方法と、CSS filter で明度・色相を反転する方法があります。フォトリアルな画像を filter: invert(1) で反転すると色調が壊れるため、重要なビジュアル素材は別ファイルで用意する方が安全です。SVGアイコン程度であれば filter での反転も実用的です。

実装の優先順位と段階的な対応

ダークモード対応を一度に完璧にしようとすると手が止まります。次のような段階で進めると現実的です。

  1. CSS変数でカラーパレットを抽象化する まずすべての色値を変数に置き換えます。この作業がない状態でテーマ切り替えを実装しようとすると、修正が散在して管理できなくなります。
  2. 背景と文字色だけ切り替える 最初のバージョンはここまでで公開できます。エフェクトは後回しでも基本的な可読性は確保できます。
  3. グロー・シャドウを調整する 実際に暗い部屋でプレイしてみて、目に刺さると感じた箇所から順に調整します。
  4. ユーザーが手動で切り替えられるようにする OS連動だけでは「作業環境はダークモードだがゲームはライトでプレイしたい」ニーズに応えられません。設定をローカルストレージに保存しておくと、次回の起動時に引き継げます。
js
function applyTheme(mode) {
  document.documentElement.setAttribute('data-theme', mode);
  localStorage.setItem('theme', mode);
}

const saved = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
applyTheme(saved ?? (prefersDark ? 'dark' : 'light'));

このコードは「保存済みの設定があればそれを優先し、なければOSの設定に従う」という最低限の仕組みです。

次の行動

まず既存のゲームのCSSを見直し、色値がハードコードされている箇所をCSS変数に置き換えるところから始めてください。その後、[data-theme="dark"] の定義を追加してブラウザの開発者ツールで属性を手動切り替えしながら表示を確認すると、問題箇所が一目でわかります。対応が一段落したら、アソバースにZIPで投稿し、実際のスマートフォン(ダークモード設定済み)でプレイして最終確認するのが確実です。

参考資料

  • WCAG(Web Content Accessibility Guidelines)— W3C
  • MDN Web Docs「prefers-color-scheme」— Mozilla
  • Colour Contrast Analyser — TPGi