🕶️

画像を dark mode 対応するメモ

2025/01/14に公開

画像をダークモード対応する方法のメモ

結論

  1. SVG は SVG 内に style でダークモードのスタイルを作成する
  2. backdroung-image は media query で切り替える
  3. img タグは <picture> を使って切り替える

web サイトでの画像をパターン分けする

画像の種類は2通りに分ける

  1. SVG 画像
  2. SVG 以外の画像

webサイトで使う画像はだいたい次のパターンに分けられる

  1. img タグで配置する画像
    1-a. SVG 画像
    1-b. SVG 以外の画像
  2. CSS の background-image で配置する画像
    2-a. SVG 画像
    2-b. SVG 以外の画像
  3. inline SVG で配置する SVG 画像

1. SVG 画像の場合

1-a. img タグで配置する SVG 画像
2-a. background-image で配置する SVG 画像
3. inline SVG 画像

1-1. SVG 内に style タグでダークモードの設定をする

SVG はコードなので内部に <style> タグを書くことができる
CSS の @media (prefers-color-scheme: dark) でダークモードを判別できるので、 SVG 内の <style> タグ内にメディアクエリでダークモードの設定を書けば oK

<svg viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
.base { fill: #66C3C4; }
.mark { fill: #FFFFFF; }
@media (prefers-color-scheme: dark) {
  .base { fill: #66C3C4; }
  .mark { fill: #FFFFFF; }
}
</style>
<path class="base" d="..." fill="#66C3C4" />
<path class="mark" d="..." fill="#FFFFFF" />
</svg>

CSS で指定できるので、複数の色が必要な画像に向いている
inline SVG だけでなく、img タグで配した SVG も background-image で読み込んだ SVG も SVG タグ内の style が効く

⚠️ 線を使っている SVG 画像は fill ではなく stroke で指定する

1-2. inline SVG の場合は CSS で設定しても良い

アイコンなどの inline SVG は fill="currentColor" として CSS の color で色を設定している場合もある。
この場合は SVG 内に style を付けてしまうと汎用性が失われるので CSS で color を変更する方が良い

1-2-1. メディアクエリで color を切り替える

<i class="icon">
  <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="..." fill="currentColor" />
  </svg>
</i>
.icon {
  color: #205081;
}
@media (prefers-color-scheme: dark) {
  .icon {
    color: #f8f5f0;
  }
}

1-2-2. CSS カスタムプロパティ(変数) にダークモードの設定をしておく

テーマが決まっているなら使用する色を CSS カスタムプロパティにしておき、予めダークモードのカラー設定をしておけばシンプルにデザインを保てる

<i class="icon">
  <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="..." fill="currentColor" />
  </svg>
</i>
:root {
  --icon-status-info: #205081;
}
@media (prefers-color-scheme: dark) {
  :root {
    --icon-status-info: #f8f5f0;
  }
}

.icon {
  color: var(--icon-status-info);
}

2. background-image の場合

2-b. background-image で配置する SVG 以外の画像

CSS なのでメディアクエリ prefers-color-scheme: dark で背景画像を変える

.content {
  background-image:url(/images/path/to/default-image.webp);
}
@media (prefers-color-scheme: dark) {
  .content {
    background-image:url(/images/path/to/darkmode-image.webp);
  }
}

3. img タグの場合

1-a. img タグで配置する SVG 以外の画像

picture / source を使って切り替える

picture / source は source のメディアクエリにマッチしたら、source で指定した画像が表示され、マッチしなければ最後の img タグがそのまま表示される機能

source タグのメディアクエリにダークモードを判定する prefers-color-scheme:dark を指定することで画像を切り替えることができるようになる

<picture>
  <source src="/images/darkmode-image.webp" media="(prefers-color-scheme:dark)" />
  <img src="images/default-image.webp" alt="" />
</picture>

srcset を使う場合

img タグは多く場合で srcset を使い画像サイズをコントロールしていると思う。
その場合も source タグにダークモード用の srcset を指定するだけで良い

<picture>
  <source
    srcset="
      /images/darkmode-image@300w.webp 300w,
      /images/darkmode-image@600w.webp 600w"
    media="(prefers-color-scheme:dark)"
  />
  <img
    src="images/default-image.webp"
    srcset="
      /images/default-image@300w.webp 300w,
      /images/default-image@600w.webp 600w"
    alt=""
  />
</picture>

favicon をダークモード対応する

  1. favicon を SVG で作成する
  2. SVG 内に style でダークモードのデザインを作成する
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">

💡 favicon として SVG が使えないブラウザは svg の方が無視される
HTML は上から読み込まれるので fallback 用のタグを上に書いておく必要がある

1 の方法と同様で SVG 内に style でダークモード用の設定を追加する

/favion.svg
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<style>
.base { fill: #fbcb62; }
.icon { fill: #2e2827; }
@media (prefers-color-scheme: dark) {
  .base { fill: #2e2827; }
  .icon { fill: #fbcb62; }
}
</style>
<path class="base" d="..." fill="#fbcb62"/>
<path class="icon" d="..." fill="#2e2827"/>
</svg>

JavaScript で ダークモードを判定する方法

window.matchMedia を使ってダークモードかどうかを判定できる

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

if (isDarkMode) {
  // darkmode の場合の処理
} else {
  // 通常の処理
}

https://developer.mozilla.org/ja/docs/Web/CSS/@media/prefers-color-scheme
https://dev.to/ziratsu/switch-to-a-darker-image-when-on-dark-mode-2lkh
https://chaika.hatenablog.com/entry/2022/03/08/083000
https://developer.mozilla.org/ja/docs/Web/CSS/Using_CSS_custom_properties
https://developer.mozilla.org/ja/docs/Web/CSS/color_value
https://zenn.dev/rabee/articles/css-tips-currentcolor
https://chaika.hatenablog.com/entry/2022/09/28/083000
https://developer.mozilla.org/ja/docs/Web/API/Window/matchMedia

Discussion