ダークモード

このページ

サイトはライトとダークの間で2つの方法のいずれかで判断します:訪問者のシステム設定、またはサイトがその訪問者に対して保存する明示的な選択です。EmDashコンポーネントは <html> 要素の規約を通じて両方のシグナルを読み取ります。このページでは、その規約、画像フィールドにダークバリアントを設定する方法、emdash/uiImage コンポーネントでレンダリングする方法を説明します。

テーマ規約

コンポーネントとテンプレートは、この順序で2つのシグナルを使用します:

  1. <html>dark または light クラスがスキームを固定します。クラスはシステム設定に優先します。
  2. クラスがない場合、スキームは prefers-color-scheme メディアクエリに従います。

バンドルされたテンプレートは明示的な選択を theme クッキーに保存し、<head> のインラインスクリプトで最初の描画前に適用します。以下のスクリプトはクッキーを読み取ってクラスを設定し、選択が保存されていない場合は何もしません:

<script is:inline>
	(function () {
		var c = document.cookie;
		var i = c.indexOf("theme=");
		var theme = i >= 0 ? c.slice(i + 6).split(";")[0] : null;
		if (theme === "dark" || theme === "light") {
			document.documentElement.classList.add(theme);
		}
	})();
</script>

light-dark() で色を一度定義し、クラスにスキームを固定させます:

:root {
	color-scheme: light dark;
	--color-bg: light-dark(#ffffff, #0d0d0d);
	--color-text: light-dark(#1a1a1a, #ededed);
}
:root.light {
	color-scheme: light;
}
:root.dark {
	color-scheme: dark;
}

テーマスイッチャーのないサイトはスクリプト不要です:<html> をクラスなしのままにすれば、システム設定が適用されます。

ダーク画像バリアント

画像フィールドにダークカラースキーム用の2番目の画像を含めることができます。エディターはプライマリ画像の横でそれを選択し、Image コンポーネントは訪問者のスキームに一致するものを表示します。

フィールドでスロットを有効にする

スロットはデフォルトで無効です。フィールドごとに管理画面またはシードファイルで有効にしてください。

管理画面で Content Types を開き、画像フィールドを編集して Dark mode variant をオンにします。

シードファイルでは、フィールドに darkVariant ウィジェットオプションを設定します:

{
	"slug": "featured_image",
	"label": "Featured Image",
	"type": "image",
	"options": { "darkVariant": true }
}

エディターでバリアントを選択する

  1. エントリを開き、通常通りプライマリ画像を選択します。

  2. 画像の下の Add dark mode variant をクリックし、メディアライブラリからダークバリアントを選択します。

  3. エントリを保存します。

バリアントはフィールド値内に darkVariant として保存されます。プライマリ画像を削除するとバリアントも削除されます。プライマリ画像を置き換えてもバリアントは保持され、置き換えるか削除するまで残ります。

バリアントをレンダリングする

Image コンポーネントは値に darkVariant が含まれている場合に両方の画像をレンダリングし、CSSで一致するものを表示します。テンプレートでは何も変わりません:

---
import { Image } from "emdash/ui";
import { getEmDashEntry } from "emdash";

const { entry: post } = await getEmDashEntry("posts", Astro.params.slug);
---

{post?.data.featured_image && <Image image={post.data.featured_image} priority />}

出力には2つの <img> 要素が含まれます。プライマリ画像にはクラス emdash-image--light が、バリアントにはクラス emdash-image--dark が付きます。両方ともプライマリ画像の alt テキスト、幅と高さのオーバーライド、ローディング属性を使用します。それぞれ独自のプレースホルダーカラーを保持します。

渡した id はプライマリ画像に残ります。バリアントは同じ id--dark サフィックスが付き、id="hero"herohero--dark になります。

ダーク画像が別の場所(2番目の画像フィールドなど)から来る場合は、明示的に渡します:

<Image image={post.data.hero} darkVariant={post.data.hero_dark} />

ローディング動作

両方の画像はデフォルトでlazyです。ブラウザは display: none で非表示になっているlazy画像をフェッチしないため、訪問者は自分のスキーム用のバリアントのみをダウンロードし、スキームが変更されたときにもう一方が読み込まれます。

priority を使用すると、両方の画像に loading="eager"fetchpriority="high" が設定され、すべてのスキームで両方がダウンロードされます。テーマはブラウザで決定されるため、サーバーは訪問者がどのバリアントを見るかわかりません。ファーストビューの1つの画像には priority を使用し、他の画像はlazyのままにしてください。

別のテーマ規約を使用する

同梱のCSSはスキームに一致しないバリアントを非表示にします。そのセレクターは <html> 部分で :where() を使用するため、クラスまたは属性で <html> をターゲットとするあなたのルールが優先します。

スイッチャーが data-theme のような属性を設定する場合、最も簡単な修正は同じコードパスから darklight クラスも設定することです。それ以外の場合は、独自のスタイルシートで4つのケースをオーバーライドします:

:root[data-theme="dark"] .emdash-image--light,
:root[data-theme="light"] .emdash-image--dark {
	display: none;
}
:root[data-theme="dark"] .emdash-image--dark,
:root[data-theme="light"] .emdash-image--light {
	display: block;
}

display 値をスタイルシートが他の場所で画像に設定しているものに合わせてください。例えば imgblock にリセットしていない場合は inline です。