tech.sinayaka.com

GatsbyJSでダークモードを導入

2023-01-28
2025-07-13
4分
790語
GatsbyJS Gatsbyjs

GatsbyJSでダークモードを実装しました。 ブラウザの設定を利用するのと手動切り替えを併せました。 「Starter」は「gatsby-starter-blog」を想定しています。

gatsby-browser.jsの編集

デフォルトのstyleでは、ダークモード時にcodeの表示が明るすぎたので、prism-twilight.cssに変更しました。
ページロード時に、 LocalStorageのキー:themeをチェック
 → darkが格納されていればbodyのclassにdarkを付与
 → 何も格納されていなければブラウザの設定に従う という内容です。

//import "prismjs/themes/prism.css"
import 'prismjs/themes/prism-twilight.css'

export const onClientEntry = () => {
    const theme = window.localStorage.getItem("theme");
    if (theme) {
        if (theme === "dark") {
            document.body.classList.add("dark");
        }
    }
    else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
        document.body.classList.add("dark");
    }
}

togglemode.jsの作成

手動でダークモードを切り替えるトグルボタンをコンポーネントで作成します。
ボタンをクリックすればLocalStorageにthemeをキーに値を保存します。 手動の設定を記憶するために、ダークではない状態をlightとして保存します。

import * as React from "react"

const ToggleMode = () => {
  const theme =() =>  {
    document.body.classList.toggle("dark")
    if (document.body.classList.contains("dark")) {
      window.localStorage.setItem("theme", "dark");
    }
    else {
      window.localStorage.setItem("theme", "light");
    }
  }
  return (
    <div>
      <button
        title="Toggle Mode"
        onClick={theme}
        className="toggle-light-dark"
      >
      </button>
    </div>
  )
}
export default ToggleMode

layout.jsの編集

サイト全体をレイアウトしている箇所でトグルボタンを設置します。

import ToggleMode from "../components/togglemode"

const Layout = ({ location, title, children }) => {
  const rootPath = `${__PATH_PREFIX__}/`
  const isRootPath = location.pathname === rootPath
  return (
    <div className="global-wrapper" data-is-root-path={isRootPath}>
      <header className="global-header">
        <h1 className="main-heading">
          <Link to="/">{title}</Link>
        </h1>
        <ToggleMode />  //設置
      </header>
      <main>{children}</main>

style.cssを編集

dark時のstyleとトグルボタンのstyleを追記します。

body.dark{
  --color-primary: #3fa3e6;
  --color-text: #fff;
  --color-text-light: #a4acb9;
  --color-heading: #ddd;
  --color-heading-black: #fff;
  --color-accent: #d1dce5;
  background-color: #1a202c;
}
.toggle-light-dark {
  border: none;
  border-radius: 4px;
}
.toggle-light-dark::after{
  content:"dark";
}
body.dark .toggle-light-dark::after{
  content:"light";
}

おわりに

フロントエンドの勉強のため、初めてGatsbyでブログをつくってみました。
Reactも触ったことがなかったのでいろいろ調べながらトライ&エラー状態です。 フロントエンド界隈は、少し前の情報でもコードの書き方が違ってたり、変化が無茶苦茶早い気がしますね。
GoogleAnalyticsの仕様も「Googleタグ」に変わっていて、 設定して「スキャン」してみてもGoogleが全然認識しなくて2日程情報を漁りまくりました。

結局「Brave」で確認してたのが原因で「Chrome」で確認したら無事認識され、トラッキングが始まりました。
「仕組み」を考えたらすぐにたどり着く答えだったのですが、 「Gatsby」のプラグインgatsby-plugin-google-gtagがもうすでに古くなっているのか? デプロイ先の「GatsbyCloud」が原因なのか? などと疑心暗鬼を発症してしまいました。

追記

上記だとロードされたあとにダークモードを判定するので、ダークモード設定されていてもページを読み込む際に一瞬ライトモードが表示されてしまいます。

ブラウザでダークモード設定されているヒトのため、デフォルトでブラウザのダークモード設定に従う旨をgatsby-ssr.jsに仕込んでおくと一瞬のライトモードを防ぐことができます。

const React = require("react");
exports.onRenderBody = ({ setPreBodyComponents }) => {
  setPreBodyComponents([
    <script
      key="set-initial-theme"
      dangerouslySetInnerHTML={{
        __html: `
          (function() {
            try {
              const theme = localStorage.getItem("theme");
              const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
              if (theme === "dark" || (!theme && prefersDark)) {
                document.body.classList.add("dark");
              }
            } catch (e) {}
          })();
        `,
      }}
    />,
  ]);
}



Copyright 2025
サイトマップ