Gatsbyにダークモードを追加する 2021.09.13
gatsby-plugin-dark-modeを追加
% yarn add gatsby-plugin-dark-mode
// gatsby-config.js
module.exports = {
plugins: ['gatsby-plugin-dark-mode'],
}
公式の通り。
ThemeTogglerを追加
見た目はあとでどうにかするとして、まず公式のcheckboxをヘッダーあたりに入れる。
// ...
import { ThemeToggler } from 'gatsby-plugin-dark-mode'
class MyComponent extends React.Component {
render() {
return (
<ThemeToggler>
{({ theme, toggleTheme }) => (
<label>
<input
type="checkbox"
onChange={e => toggleTheme(e.target.checked ? 'dark' : 'light')}
checked={theme === 'dark'}
/>{' '}
Dark mode
</label>
)}
</ThemeToggler>
)
}
}
tailwindcssのダークモードを有効にする
The
media
strategy uses theprefers-color-scheme
media feature under the hood, but if you’d like to support toggling dark mode manually, you can also use the ‘class’ strategy for more control.
class
を指定することで、メディアクエリとマニュアル操作の両方に対応できるらしい。
// tailwind.config.js
module.exports = {
darkMode: 'class',
// ...
}
body
要素にダークモードを適用する場合はglobal.cssに指定する
html.jsを追加してカスタマイズしてあっても、body
要素に対してtailwindcssのdark:
バリアントは効かないので、body
に対してダークモードを適用するにはglobal.cssに指定する。
body.dark {
@apply bg-gray-900;
}
tailwindcss-typographyにダークモードを適用する
prose
クラスが指定されている要素にdark:prose-dark
を追加。
<main className="prose-sm md:prose dark:prose-dark"></main>
tailwind.config.jsにvariants.extend.typography
とtheme.extend.typography.dark
を追加。
module.exports = {
theme: {
extend: {
typography: {
DEFAULT: {},
dark: {
css: {
color: colors.warmGray['50'],
},
},
},
},
},
variants: {
extend: {
typography: ['dark'],
},
},
}
あとは、必要な要素に対してdark:
バリアントを指定したり、あるいは、.dark
クラスの子孫要素に対してスタイリングしていく。
Prismのテーマを切り替える
ダークモードのときはsyntax highlightingのテーマも変えたい。
global.cssをSCSSにして、ネストされた @import
でダークモード用のテーマを適用する。
まず、SCSSを使えるようにする。
% yarn add sass gatsby-plugin-sass
// gatsby-config.js
module.exports = {
plugins: [
'gatsby-plugin-sass',
],
};
global.cssをglobal.scssに変更して、ダークモード用のテーマを追加。
.dark {
@import "prism-themes/themes/prism-hopscotch";
}
このとき、パスに.css
拡張子をつけると読み込めないので注意。
In addition to importing .sass and .scss files, Sass can import plain old .css files. The only rule is that the import must not explicitly include the .css extension, because that’s used to indicate a plain CSS @import.
初期表示のときprefered-color-schemeが反映されない
端末をダークモードにして開発サイトにアクセスしてもダークモードに切り替わらない。
プラグインの処理を見ると、localStorageに保存されている状態が優先されているようだ。
void function() {
window.__onThemeChange = function() {}
var preferredTheme
try {
preferredTheme = localStorage.getItem('theme')
} catch (err) { }
// ...
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
darkQuery.addListener(function(e) {
window.__setPreferredTheme(e.matches ? 'dark' : 'light')
})
setTheme(preferredTheme || (darkQuery.matches ? 'dark' : 'light'))
}()
これでもいいんだけど、例えばGitHubなんかはそうなってない気がする。
個人的にはMacのダークモードを自動にしているので、サイトのダークモードもそれに合わせてほしい。
今回は端末の設定に合わせるのが優先で、それが嫌な人は手動で切り替えてね、とする。
gatsby-plugin-dark-modeから、gatsby-ssr.jsとThemeToggler.jsを取り出して自分のsrc
に配置。
gatsby-ssr.jsのダークモードの処理を変更する。
void function() {
window.__onThemeChange = function() {}
var preferredTheme
- try {
- preferredTheme = localStorage.getItem('theme')
- } catch (err) { }
// ...
window.__setPreferredTheme = function(newTheme) {
setTheme(newTheme)
- try {
- localStorage.setItem('theme', newTheme)
- } catch (err) {}
}
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
darkQuery.addListener(function(e) {
window.__setPreferredTheme(e.matches ? 'dark' : 'light')
})
- setTheme(preferredTheme || (darkQuery.matches ? 'dark' : 'light'))
+ setTheme(darkQuery.matches ? 'dark' : 'light')
}()
期待した動作になったので、gatsby-plugin-dark-modeは削除した。
Gatsbyにダークモードを導入することができた。