Um site decide entre claro e escuro de uma de duas maneiras: a preferência do sistema do visitante, ou uma escolha explícita que o site armazena para esse visitante. Os componentes EmDash leem ambos os sinais através de uma convenção no elemento <html>. Esta página descreve essa convenção, como dar a um campo de imagem uma variante escura e como renderizá-la com o componente Image de emdash/ui.
Convenção de tema
Componentes e templates usam estes dois sinais, nesta ordem:
- Uma classe
darkoulightno<html>fixa o esquema. A classe vence sobre a preferência do sistema. - Sem classe, o esquema segue a media query
prefers-color-scheme.
Os templates incluídos armazenam uma escolha explícita em um cookie theme e a aplicam antes do primeiro paint com um script inline no <head>. O script a seguir lê o cookie e define a classe, e não faz nada quando nenhuma escolha está armazenada:
<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>
Defina cores uma vez com light-dark() e deixe a classe fixar o esquema:
: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;
}
Um site sem alternador de tema não precisa de script: deixe <html> sem classe e a preferência do sistema se aplica.
Variantes escuras de imagem
Um campo de imagem pode carregar uma segunda imagem para esquemas de cores escuros. Editores a escolhem ao lado da imagem principal, e o componente Image mostra a que corresponde ao esquema do visitante.
Ativar o slot em um campo
O slot está desativado por padrão. Ative-o por campo, seja no admin ou em um arquivo seed.
No admin, abra Content Types, edite o campo de imagem e ative Dark mode variant.
Em um arquivo seed, defina a opção de widget darkVariant no campo:
{
"slug": "featured_image",
"label": "Featured Image",
"type": "image",
"options": { "darkVariant": true }
}
Escolher a variante no editor
-
Abra uma entrada e selecione a imagem principal como de costume.
-
Clique em Add dark mode variant abaixo da imagem e escolha a variante escura da biblioteca de mídia.
-
Salve a entrada.
A variante é armazenada dentro do valor do campo como darkVariant. Remover a imagem principal remove a variante junto; substituir a imagem principal mantém a variante até você substituí-la ou removê-la.
Renderizar a variante
O componente Image renderiza ambas as imagens quando o valor carrega uma darkVariant e mostra a correspondente com CSS. Nada muda no template:
---
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 />}
A saída contém dois elementos <img>. A imagem principal recebe a classe emdash-image--light e a variante recebe emdash-image--dark. Ambas usam o texto alternativo, as sobrecargas de largura e altura, e os atributos de carregamento da imagem principal. Cada uma mantém sua própria cor de placeholder.
Um id que você passa fica na imagem principal; a variante recebe o mesmo id com um sufixo --dark, então id="hero" produz hero e hero--dark.
Quando a imagem escura vem de outro lugar, como um segundo campo de imagem, passe-a explicitamente:
<Image image={post.data.hero} darkVariant={post.data.hero_dark} />
Comportamento de carregamento
Ambas as imagens são lazy por padrão. Navegadores não buscam uma imagem lazy que está oculta com display: none, então um visitante baixa apenas a variante para seu esquema, e a outra carrega quando o esquema muda.
Com priority, ambas as imagens recebem loading="eager" e fetchpriority="high", e ambas são baixadas em cada esquema. O tema é decidido no navegador, então o servidor não pode saber qual variante um visitante verá. Use priority na única imagem acima da dobra e deixe as outras imagens lazy.
Usar uma convenção de tema diferente
O CSS incluído oculta a variante que não corresponde ao esquema. Seus seletores usam :where() na parte do <html>, então qualquer regra sua que aponte para <html> com uma classe ou atributo vence.
Se seu alternador define um atributo como data-theme, a correção mais curta é também definir as classes dark e light do mesmo caminho de código. Caso contrário, sobrescreva os quatro casos em sua própria folha de estilos:
: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;
}
Combine o valor de display com o que sua folha de estilos dá às imagens em outros lugares, por exemplo inline quando você não redefine img para block.