[Astro] prefers-color-scheme で自動ダークモード対応にする
Techこのブログは、OS のテーマ設定に合わせて自動でダークモードに切り替わるようにしています。トグルボタンは置かず、prefers-color-scheme に任せるシンプルな方式です。実装をまとめます。
方針:トグルなし、OS追従
ダークモードには「ボタンで手動切替」と「OS設定に追従」の2方式がありますが、個人ブログなら OS追従が一番ラクです。状態管理もlocalStorageも要りません。CSS だけで完結します。
ベースの配色を CSS で切り替える
body などの基本色は、@media (prefers-color-scheme: dark) で上書きします。
/* src/styles/global.css */
body {
color: var(--color-text);
background-color: var(--color-bg);
}
@media (prefers-color-scheme: dark) {
body {
color: #e0e0e0;
background-color: #1a1a2e;
}
}
コンポーネントは Tailwind の dark: で
個別要素は Tailwind の dark: バリアントで指定します。Tailwind CSS v4 の dark: は、デフォルトで prefers-color-scheme: dark に対応しているので、設定不要でそのまま使えます(クラス方式にしたい場合だけ @custom-variant の設定が要る)。
<body class="bg-[var(--color-bg)] text-[var(--color-text)] dark:bg-[#1a1a2e] dark:text-[#e0e0e0]">
カードなども同様に。
<div class="bg-white dark:bg-[#16213e] ...">
CSS変数(--color-*)でライト配色を定義しておき、ダークは dark: で個別に当てる、という併用にしています。
記事本文(prose)も忘れずに
Typography プラグインの prose は、ダーク用に dark:prose-invert を足すだけで本文の文字色などが反転します。
<div class="prose prose-lg dark:prose-invert max-w-none">
<slot />
</div>
コードハイライト(Shiki)のダーク対応は別途必要ですが、それは別記事にまとめています。
メモ
- OS追従は実装が最小で、状態のズレも起きない。個人ブログには十分。
- Tailwind v4 の
dark:はデフォルトでprefers-color-schemeベース。クラストグルにしたいときだけ@custom-variant dark (&:where(.dark, .dark *));のような設定を足す。 - 確認は OS のダークモードを切り替えるか、ブラウザの DevTools で
prefers-color-schemeをエミュレートするのが早い。
ボタンを置かない割り切りで、コードはかなりスッキリしました。
Astro, Tailwind CSS, CSS