다크 모드

이 페이지

사이트는 두 가지 방법 중 하나로 라이트와 다크를 결정합니다: 방문자의 시스템 설정 또는 사이트가 해당 방문자를 위해 저장하는 명시적 선택입니다. EmDash 컴포넌트는 <html> 요소의 규약을 통해 두 신호를 읽습니다. 이 페이지에서는 그 규약, 이미지 필드에 다크 변형을 제공하는 방법, emdash/uiImage 컴포넌트로 렌더링하는 방법을 설명합니다.

테마 규약

컴포넌트와 템플릿은 이 순서로 두 가지 신호를 사용합니다:

  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>을 클래스 없이 두면 시스템 설정이 적용됩니다.

다크 이미지 변형

이미지 필드는 다크 색상 구성표용 두 번째 이미지를 포함할 수 있습니다. 편집자는 기본 이미지 옆에서 선택하고, 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 />}

출력에는 두 개의 <img> 요소가 포함됩니다. 기본 이미지는 클래스 emdash-image--light를, 변형은 emdash-image--dark를 받습니다. 둘 다 기본 이미지의 alt 텍스트, 너비 및 높이 오버라이드, 로딩 속성을 사용합니다. 각각 자체 플레이스홀더 색상을 유지합니다.

전달하는 id는 기본 이미지에 유지됩니다. 변형은 동일한 id--dark 접미사가 붙어, id="hero"herohero--dark를 생성합니다.

다크 이미지가 다른 곳(예: 두 번째 이미지 필드)에서 오는 경우 명시적으로 전달합니다:

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

로딩 동작

두 이미지는 기본적으로 lazy입니다. 브라우저는 display: none으로 숨겨진 lazy 이미지를 가져오지 않으므로, 방문자는 자신의 구성표에 맞는 변형만 다운로드하고 구성표가 변경될 때 다른 것이 로드됩니다.

priority를 사용하면 두 이미지 모두 loading="eager"fetchpriority="high"를 받고, 모든 구성표에서 둘 다 다운로드됩니다. 테마는 브라우저에서 결정되므로 서버는 방문자가 어떤 변형을 볼지 알 수 없습니다. 스크롤 없이 볼 수 있는 하나의 이미지에는 priority를 사용하고 다른 이미지는 lazy로 두세요.

다른 테마 규약 사용

제공된 CSS는 구성표와 일치하지 않는 변형을 숨깁니다. 셀렉터는 <html> 부분에서 :where()를 사용하므로, 클래스나 속성으로 <html>을 대상으로 하는 어떤 규칙이든 우선합니다.

스위처가 data-theme과 같은 속성을 설정하는 경우, 가장 간단한 수정은 같은 코드 경로에서 darklight 클래스도 설정하는 것입니다. 그렇지 않으면 자체 스타일시트에서 네 가지 경우를 오버라이드하세요:

: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입니다.