サイトはライトとダークの間で2つの方法のいずれかで判断します:訪問者のシステム設定、またはサイトがその訪問者に対して保存する明示的な選択です。EmDashコンポーネントは <html> 要素の規約を通じて両方のシグナルを読み取ります。このページでは、その規約、画像フィールドにダークバリアントを設定する方法、emdash/ui の Image コンポーネントでレンダリングする方法を説明します。
テーマ規約
コンポーネントとテンプレートは、この順序で2つのシグナルを使用します:
<html>のdarkまたはlightクラスがスキームを固定します。クラスはシステム設定に優先します。- クラスがない場合、スキームは
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 }
}
エディターでバリアントを選択する
-
エントリを開き、通常通りプライマリ画像を選択します。
-
画像の下の Add dark mode variant をクリックし、メディアライブラリからダークバリアントを選択します。
-
エントリを保存します。
バリアントはフィールド値内に 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" は hero と hero--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 のような属性を設定する場合、最も簡単な修正は同じコードパスから dark と light クラスも設定することです。それ以外の場合は、独自のスタイルシートで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 値をスタイルシートが他の場所で画像に設定しているものに合わせてください。例えば img を block にリセットしていない場合は inline です。