はじめに

この記事ではMUIで「ダークモード」の概要と対応する手順を簡単にまとめています。

「ダークモード」とは

「ダークモード」は現在様々なアプリやサイトで使用されています。
すでに説明不要かもしれませんが、「ダークモード」とは、暗めの色調の表示モード(暗めの色を基調に文字色に白系の色)にできる機能です。対して「ライトモード」とは、明るめの色調の表示モード(白系の色を基調に文字に暗めの色)にできる機能です。

「ダークモード」のメリット

期待できるメリットとして

  • 見た目の好み
  • 眼精疲労の軽減(特に暗い環境の場合:周囲の環境とのコントラスト比が低い方が目への負担が減るため)
  • 省電力、バッテリーの節約、画面の劣化/焼き付き防止(「有機ELディスプレイ(OLED)」の場合)

上記が挙げられます。

実際に試してみる

今回はReact+MUIを使用してダークモードとライトモードをトグルスイッチで切り替えられるところまで試していきます。
まずはReact環境にMUIをインストールしていきます。デフォルトでインストールするものに加えてアイコンを使用するために@mui/icons-materialも加えます。

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material

インストール完了後、src/App.jsに移動し、ファイルの既存のコードを次の例に置き換えます。

import { ThemeProvider, createTheme } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { Box } from "@mui/material";

// アイコンを使用
import DarkModeIcon from "@mui/icons-material/DarkMode";

export default function App() {

  // テーマ'dark'を反映するための関数
  const darkTheme = createTheme({
    palette: {
      mode: "dark",
    },
  });

  return (
    <ThemeProvider theme={darkTheme}>
      <CssBaseline />
      <Box
        sx={{
          display: "flex",
          alignItems: "center",
          alignSelf: "center",
          flexDirection: "column",
          paddingTop: "48px",
          gap: "16px",
        }}
      >
        <Box>
             <DarkModeIcon />
        </Box>
      </Box>
    </ThemeProvider>
  );
}

ブラウザで表示するとこのように表示されます。

ちなみにCssBaselineについて
コードの中身に CssBaseline があります。これは、MUI が用意しているブラウザ間の見た目の差をなくすためのリセットCSSと似た働きをするノーマライズCSSです。
ThemeProviderコンポーネントの中に CssBaseline を追加することで背景のダークモードも有効になります。

ノーマライズCSSはブラウザデフォルトのCSSの違いを統一して、見た目を整えることが中心のCSSです。
ノーマライズCSSの場合は“統一された、実用的なデフォルトスタイルの設定”が目的。リセットCSSのように、hタグのサイズがpタグと同じになったりはしません。
cssゼロ状態から設定するほどではない、という場合に適しているでしょう。

https://skillhub.jp/blogs/285#skillhub-subchapter-2-1

次にダークモードとライトモードの切り替えができるようにしていきます。
まずは、状態管理のためのuseState、切り替えのためのトグルスイッチ(Switch)、ライトモード用のアイコンを追加します。

// 状態管理のためにuseStateを追加
import { useState } from "react";
// 切り替えるためのSwitchを追加
import { Switch, Box } from "@mui/material";
// ライトモード用のLightModeIconを追加
import LightModeIcon from "@mui/icons-material/LightMode";

次に初期値と関数を追加していきます。

  //const [状態変数, 状態を変更するための関数] = useState(状態の初期値);
  const [toggleDarkMode, setToggleDarkMode] = useState(true);

  // ダークモードをtrueとfalseで切り替える関数を宣言
  const toggleDarkTheme = () => {
    setToggleDarkMode(!toggleDarkMode);
  };

  // テーマに現状のモードを確認して'dark'あるいは'light'を反映するための関数
  const theme = createTheme({
    palette: {
      mode: toggleDarkMode ? "dark" : "light",
    },
  });

そしてダークモードアイコンを表示していた部分にライトモードアイコンを追加します。

<Switch checked={toggleDarkMode} onChange={toggleDarkTheme} />
<Box onChange={toggleDarkTheme}>
  {toggleDarkMode ? <DarkModeIcon /> : <LightModeIcon />}
</Box>

これでダークモードとライトモードを切り替えができるようになりました。

最後に初期表示時にシステム設定に基づいたモードになるよう追加していきます。
CSSではprefers-color-schemeというCSS のメディア特性であり、ユーザーがシステムに要求したカラーテーマが明色か暗色かを検出するためのものがあります。

@media (prefers-color-scheme: dark) {
    background-color: black;
}
@media (prefers-color-scheme: light) {
    background-color: white;
}

上記のように@mediaを使用してシステムで「ユーザーがシステムに要求したカラーテーマが明色か暗色かを検出」して色をモードに合わせて設定することができます。

こちらを利用してシステム設定に基づいたモードになるようにしていきます。

 // 追加
import useMediaQuery from "@mui/material/useMediaQuery";

export default function App() {
  // 追加 useMediaQuery()を使用してユーザーがシステムに要求したカラーテーマを検出
  const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)"); 
  // const [状態変数, 状態を変更するための関数] = useState(状態の初期値);
  // 初期値にprefersDarkModeを設定
  const [toggleDarkMode, setToggleDarkMode] = useState(prefersDarkMode);

ユーザーがシステムに要求したカラーテーマを検出して初期値にシステムで設定されたカラーモードを設定して初期表示に適用することができます。

最終的にブラウザ表示した結果がこちらです。初期表示はシステム設定に依存してスイッチで切り替えることができます。

また、最近ではChrome 123やFirefox 120以降で使用できる機能でlight-dark()があります。この関数を使用するとライトモードの時とダークモードの時の色がわかりやすく、メディアクエリーの場合と同様にシステムで「ユーザーがシステムに要求したカラーテーマが明色か暗色かを検出」して色を表示分けすることができます。

.background {
    background-color: light-dark(black, white);
}

まとめ

ダークモード対応は、実際に試してみることで意外と簡単に適用できることがわかりました。対応するにあたり、色の表示分け自体は組み込みやすさがありますが、疲れにくい色の組み合わせ(特に日常的な利用や長時間の使用が想定される場合)や奥行き表現、画像、可読性、要素同士の区別のつきやすさなどデザイン上考慮すべき点があります。ユーザーにメリットもありますが実現するために、考慮すべき点を考慮した上で実際にサイトに組み込んでいきましょう。

参考
ダークモードとライトモード:どちらが良いのか
https://u-site.jp/alertbox/dark-mode

ダークモード:ユーザーの考え方と避けるべき課題
https://u-site.jp/alertbox/dark-mode-users-issues

ダークモードを巡るあれこれ:ダークモードの明るい未来
https://techblog.enechain.com/entry/dark-mode-2023

Dark mode – Material UI
https://mui.com/material-ui/customization/dark-mode/

prefers-color-scheme – CSS: カスケーディングスタイルシート | MDN
https://developer.mozilla.org/ja/docs/Web/CSS/@media/prefers-color-scheme

light-dark() – CSS: カスケーディングスタイルシート | MDN
https://developer.mozilla.org/ja/docs/Web/CSS/@media/prefers-color-scheme