GatsbyJS製のブログをダークモードに対応させる

GatsbyJS 製のこのブログをダークモードに対応させたので実装法を書く。

ダークモードの対応は基本的には以下のメディアクエリで各テーマ毎の css を書くだけでいい。
コンポーネント毎に対応していくのは面倒なので 各プロパティ値を css valiables で定義してテーマ毎に切り替えた方が シンプルにできる。

@media (prefers-color-scheme: dark) {
  /* dark mode style */
}

@media (prefers-color-scheme: light) {
  /* light mode style */
}

今回はgatsby-plugin-dark-modeを使ったけど仕組み的には選択してるテーマに応じてクラスが付与されるだけなのでプラグインを使わなくても以下のコードだけで実装可能。

const setTheme = newTheme => (document.body.className = newTheme)

const query = window.matchMedia('(prefers-color-scheme: dark)')
query.addListener(e => setTheme(e.matches ? 'dark' : 'light'))

setTheme(query.matches ? 'dark' : 'light')

プラグインの場合は localStorage にテーマが保存されるようになっているので、手動でテーマを切り替えても動作するようになってます。 後はテーマ毎に css valiables を設定して各コンポーネントに反映させていけば終了。

body {
  --bg: white;
  --bgーarticle: white;
  --text-normal: rgba(0, 0, 0, 0.8);
  --text-title: white;
  --text-link: blue;
  --text-link-hover: blue;
  --ui-colors-b: #0b5575;

  background-color: var(--bg);
}

body.dark {
  --bg: #020411;
  --bgーarticle: #1f1f2d;
  --text-normal: rgba(255, 255, 255, 0.87);
  --text-title: rgba(255, 255, 255, 0.87);
  --text-link: rgb(157, 184, 242);
  --text-link-hover: rgb(111, 152, 255);
  --ui-colors-b: #071446;
}

こちらの記事に書いてあるようにダークモードではドロップシャドウで要素の階層構造を表現しにくいので、ドロップシャドウを使ってる箇所はデザインを修正する必要があるので注意。

styled-components を使ってれば ThemeProvider で対応する方法もある。

参考