🔦
Astro + daisyUIのサイトのダークモード対応
Astro + daisyUIで構築している自分のWebサイトをダークモード対応した際のメモ。
環境
package.json
{
"dependencies": {
"astro": "^5.9.2",
"daisyui": "^5.0.43"
}
}
テーマ切り替えUIの追加
まず、ライトモードとダークモードを切り替えるスイッチを追加。
daisyUIにはTheme Controllerというテーマ切り替え用コンポーネントが用意されているので、これを利用。
ダークモードのテーマはnight
を採用。
ライトモードのテーマ:にはcorporate
を使っていたが、corporate
とnight
ではスイッチの形状が異なり、切り替え時に違和感があったため、形状が近いwinter
に変更。
ダークモード時の見た目調整
- GitHubやXのSVGアイコンに
fill-base-content
を指定し、暗色背景でも視認できるようにした - カードはshadowだけだと境界が見えづらくなるため、
border
を追加
LocalStorageにテーマを保存
Theme Controllerはページ単位でしかテーマを切り替えられないため、画面遷移やリロードでデフォルトに戻ってしまう。 そこで、LocalStorageに選択したテーマを保存し、ロード時に反映する処理を追加した。LocalStorageに値がない場合、OSがダークモードならnight
を適用するようにした。
今回はVanilla JSで実装したが、将来的にTypeScript化したい。
Header.astro
<script>
const themeController = document.querySelector('.theme-controller');
if (themeController) {
const theme = (() => {
if (
typeof localStorage !== 'undefined' &&
localStorage.getItem('theme')
) {
return localStorage.getItem('theme');
}
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'night';
}
return 'winter';
})();
const setTheme = (theme) => {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
if (themeController instanceof HTMLInputElement) {
themeController.checked = theme === 'night';
}
};
themeController.addEventListener('change', (e) => {
const target = e.target;
setTheme(target.checked ? 'night' : 'winter');
});
setTheme(theme);
}
</script>
ちらつき対策
ダークモード時、画面遷移時に一瞬ライトモードが表示されるちらつきが発生。
原因はデフォルトモードの状態で描画されてからJSで切り替えているため。
MPAの性質上仕方ないと思っていたが、View Transitionを導入することで解消した。
-
ClientRouter
を有効化 - スイッチ状態を保持するため、input要素に
transition:persist
を追加 -
astro:after-swap
イベントでの再設定は不要だった(公式ドキュメントのケースは<script is:inline>
の場合だから必要なんだと思うが、ちゃんと理解できていない)
まとめ
daisyUIのTheme Controllerを使って、ダークモードに対応した。
想定外だったMPAのちらつき問題は、View Transition
を導入して解消できた。
結果として、サイト全体のクオリティを向上できた。
ソースコード
Discussion