サイトは、ライトとダークのどちらを使うかを、2 つの方法のいずれかで決めます。訪問者のシステム設定、またはサイトがその訪問者のために保存した明示的な選択です。EmDash のコンポーネントは、<html> 要素上の 1 つの規約を通じて、この両方のシグナルを読み取ります。このページでは、その規約、画像フィールドにダークバリアントを持たせる方法、そして emdash/ui の Image コンポーネントでレンダリングする方法を説明します。
テーマ規約
コンポーネントとテンプレートは、次の順序でこの 2 つのシグナルを使用します。
<html>上のdarkまたはlightクラスがカラースキームを固定します。このクラスはシステム設定より優先されます。- クラスがない場合、カラースキームは
prefers-color-schemeメディアクエリに従います。
付属のテンプレートは、明示的な選択を theme Cookie に保存し、<head> 内のインラインスクリプトで最初の描画の前に適用します。次のスクリプトは Cookie を読み取ってクラスを設定し、選択が保存されていない場合は何もしません。
<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 として保存されます。プライマリ画像を削除するとバリアントも一緒に削除されます。プライマリ画像を置き換えた場合、バリアントを置き換えるか削除するまで保持されます。
バリアントをレンダリングする
値に darkVariant が含まれていると、Image コンポーネントは両方の画像をレンダリングし、CSS で一致するほうを表示します。テンプレートには何も変更はありません。
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { Image } from "emdash/ui";
const slug = decodeSlug(Astro.params.slug);
if (!slug) {
return Astro.rewrite("/404");
}
const { entry: post } = await getEmDashEntry("posts", slug);
if (!post) {
return Astro.rewrite("/404");
}
---
{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} />
読み込み動作
どちらの画像も、デフォルトで遅延読み込みになります。ブラウザーは display: none で非表示になっている遅延読み込みの画像を取得しないため、訪問者は自分のスキームに合うバリアントだけをダウンロードし、もう一方はスキームが変わったときに読み込まれます。
priority を指定すると、両方の画像に loading="eager" と fetchpriority="high" が設定され、どのスキームでも両方がダウンロードされます。テーマはブラウザーで決まるため、サーバーは訪問者がどちらのバリアントを見るかを判断できません。priority はファーストビューの 1 枚の画像にだけ使用し、他の画像は遅延読み込みのままにしてください。
別のテーマ規約を使用する
同梱の 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 です。