Gatsby.jsにDarkModeを導入する

一番お手軽だと思われる、gatsby-plugin-dark-mode を使います。
ちなみに現在のモードは localStrage に保存されます。

プラグインインストール

yarn add gatsby-plugin-dark-mode
gatsby-config.js
module.exports = {
  plugins: ['gatsby-plugin-dark-mode'],
}

## コンポーネント作成

スイッチするためのコンポーネントを作ります。
toggleTheme()でスイッチするためだけのものなので、必ず新規でコンポーネントを作る必要はありません。 よきところにを置けばいいだけです。

C:/src/components/mode.js
import React from 'react'
import { ThemeToggler } from 'gatsby-plugin-dark-mode'

class mode extends React.Component {
  render() {
    return (
      <ThemeToggler>
        {({ theme, toggleTheme }) => {
          // Don't render anything at compile time. Deferring rendering until we
          // know which theme to use on the client avoids incorrect initial
          // state being displayed.
          if (theme == null) {
            return null
          }
          return (
            <label>
              <input
                type="checkbox"
                onChange={e => toggleTheme(e.target.checked ? 'dark' : 'light')}
                checked={theme === 'dark'}
              />{' '}
              Dark mode
            </label>
          )
        }}
      </ThemeToggler>
    )
  }
}

テーマをつくる

各種定義はいい感じに修正します。

global.css
body {
  --bg: white;
  --textNormal: #222;
  --textTitle: #222;
  --textLink: blue;
  --hr: hsla(0, 0%, 0%, 0.2);

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

body.dark {
  -webkit-font-smoothing: antialiased;

  --bg: darkslategray;
  --textNormal: rgba(255, 255, 255, 0.88);
  --textTitle: white;
  --textLink: yellow;
  --hr: hsla(0, 0%, 100%, 0.2);
}

テーマを適用する

src/components/layout.js
class Layout extends React.Component {
  render() {
    return (
      <div
        style={{
          backgroundColor: 'var(--bg)',
          color: 'var(--textNormal)',
          transition: 'color 0.2s ease-out, background 0.2s ease-out',
        }}
      >
        ...
      </div>
    )
  }
}

typography を導入していた場合、そこにダークモードを適用の仕方はこんな感じ。

src/utils/Typography.js
…
theme.overrideThemeStyles = ({ rhythm }, options) => ({
  'h2,h3,h4,h5': {
    marginBottom: rhythm(1 / 2),
    marginTop: rhythm(2),
  },
  a: {    color: 'var(--textLink)',  },  // gatsby-remark-autolink-headers - don't underline when hidden  'a.anchor': {    boxShadow: 'none',  },  // gatsby-remark-autolink-headers - use theme colours for the link icon  'a.anchor svg[aria-hidden="true"]': {    stroke: 'var(--textLink)',  },  hr: {    background: 'var(--hr)',  },})

参考