このサイトの右上には、昼・夕暮れ・夜を切り替えるスイッチがあります。ダークモードの拡張版のような機能ですが、仕組みはほぼCSSだけでできています。
カスタムプロパティをモードで束ねる
ルート要素の属性ひとつで、空・文字・カード・草原の色がまとめて切り替わります。
[data-mode="night"] {
--sky-top: #0a0e2a;
--sky-mid: #141a44;
--sky-bot: #243056;
--ink: #eef2ff;
}
[data-mode="dusk"] {
--sky-top: #2a1a47;
--sky-mid: #7a3b6b;
--sky-bot: #e8814f;
--ink: #fff3ec;
}
コンポーネント側は var(--sky-top) を参照するだけ。モードが増えても触るのは変数定義だけです。
空は transition でぬるっと移ろわせる
背景のグラデーションに長めの transition を当てると、空が時間とともに移ろうような演出になります。
.sky {
background: linear-gradient(180deg, var(--sky-top), var(--sky-mid), var(--sky-bot));
transition: background 1100ms cubic-bezier(0.22, 1, 0.36, 1);
}
星は消さずに、薄くする
星空は要素の付け外しではなく、不透明度の変数で表現しています。夜は 1、夕暮れは 0.45、昼は 0。DOMを触らないので軽量で、モード切替のたびに星が再生成されることもありません。
チラつき対策は「ペイント前の3行」
選んだモードは localStorage に保存していますが、復元のタイミングを誤ると、リロード時に一瞬デフォルトの夜が見えてから昼に切り替わる「フラッシュ」が起きます。対策は、<head> の中に同期実行のインラインスクリプトを置くことです(Astroなら is:inline を付けて、バンドル対象から外します)。
var m = localStorage.getItem("mode") || "night";
document.documentElement.setAttribute("data-mode", m);
最初の描画より前に属性が確定するので、どのモードを選んでいてもチラつきません。
JavaScriptの仕事は「属性の切り替え」と「保存・復元」だけ。残りを全部CSSに任せるのが、軽くて壊れにくい作り方だと思います。