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) {}
})();
`,
}}
/>,
]);
}