サイトはライトとダークを2つの方法のいずれかで決定します:訪問者のシステム設定、またはサイトがその訪問者のために保存する明示的な選択です。EmDash コンポーネントは <html> 要素の1つの規約を通じて両方のシグナルを読み取ります。このページではその規約、画像フィールドにダークバリアントを設定する方法、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 { decodeSlug, getEmDashEntry } from "emdash";
import { Image } from "emdash/ui";
const slug = decodeSlug(Astro.params.slug);
if (!slug) {
return Astro.redirect("/404");
}
const { entry: post } = await getEmDashEntry("posts", slug);
if (!post) {
return Astro.redirect("/404");
}
---
{post.data.featured_image && <Image image={post.data.featured_image} priority />}
出力には2つの <img> 要素が含まれます。プライマリ画像はクラス emdash-image--light を取得し、バリアントは emdash-image--dark を取得します。両方ともプライマリ画像の代替テキスト、幅と高さのオーバーライド、読み込み属性を使用します。それぞれ独自のプレースホルダーカラーを保持します。
渡した 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 です。