Un sitio decide entre claro y oscuro de dos maneras: la preferencia del sistema del visitante o una elección explícita que el sitio almacena para ese visitante. Los componentes de EmDash leen ambas señales a través de una convención en el elemento <html>. Esta página describe esa convención, cómo dar a un campo de imagen una variante oscura y cómo renderizarla con el componente Image de emdash/ui.
Convención del tema
Los componentes y plantillas usan estas dos señales, en este orden:
- Una clase
darkolighten<html>fija el esquema. La clase prevalece sobre la preferencia del sistema. - Sin clase, el esquema sigue la media query
prefers-color-scheme.
Las plantillas incluidas almacenan una elección explícita en una cookie theme y la aplican antes del primer pintado con un script inline en <head>. El siguiente script lee la cookie y establece la clase, y no hace nada cuando no hay elección almacenada:
<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 colores una vez con light-dark() y deje que la clase fije el 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;
}
Un sitio sin selector de tema no necesita script: deje <html> sin clase y la preferencia del sistema se aplica.
Variantes de imagen oscura
Un campo de imagen puede llevar una segunda imagen para esquemas de color oscuros. Los editores la seleccionan junto a la imagen principal, y el componente Image muestra la que coincide con el esquema del visitante.
Habilitar el slot en un campo
El slot está desactivado por defecto. Actívelo por campo, ya sea en el admin o en un archivo seed.
En el admin, abra Content Types, edite el campo de imagen y active Dark mode variant.
En un archivo seed, establezca la opción de widget darkVariant en el campo:
{
"slug": "featured_image",
"label": "Featured Image",
"type": "image",
"options": { "darkVariant": true }
}
Elegir la variante en el editor
-
Abra una entrada y seleccione la imagen principal como siempre.
-
Haga clic en Add dark mode variant debajo de la imagen y elija la variante oscura de la biblioteca de medios.
-
Guarde la entrada.
La variante se almacena dentro del valor del campo como darkVariant. Eliminar la imagen principal elimina la variante con ella; reemplazar la imagen principal mantiene la variante hasta que la reemplace o elimine.
Renderizar la variante
El componente Image renderiza ambas imágenes cuando el valor contiene un darkVariant y muestra la correspondiente con CSS. Nada cambia en la plantilla:
---
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 />}
La salida contiene dos elementos <img>. La imagen principal obtiene la clase emdash-image--light y la variante obtiene emdash-image--dark. Ambas usan el texto alt, las sobrecargas de ancho y alto, y los atributos de carga de la imagen principal. Cada una mantiene su propio color de marcador de posición.
Un id que pase se queda en la imagen principal; la variante obtiene el mismo id con un sufijo --dark, así que id="hero" produce hero y hero--dark.
Cuando la imagen oscura proviene de otro lugar, como un segundo campo de imagen, pásela explícitamente:
<Image image={post.data.hero} darkVariant={post.data.hero_dark} />
Comportamiento de carga
Ambas imágenes son lazy por defecto. Los navegadores no descargan una imagen lazy que está oculta con display: none, así que un visitante descarga solo la variante para su esquema, y la otra se carga cuando el esquema cambia.
Con priority, ambas imágenes obtienen loading="eager" y fetchpriority="high", y ambas se descargan en todos los esquemas. El tema se decide en el navegador, por lo que el servidor no puede saber qué variante verá un visitante. Use priority en la imagen que está por encima del pliegue y deje las demás lazy.
Usar una convención de tema diferente
El CSS incluido oculta la variante que no coincide con el esquema. Sus selectores usan :where() en la parte <html>, por lo que cualquier regla suya que apunte a <html> con una clase o atributo prevalece.
Si su selector establece un atributo como data-theme, la solución más corta es también establecer las clases dark y light desde la misma ruta de código. De lo contrario, sobrescriba los cuatro casos en su propia hoja 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;
}
Haga coincidir el valor de display con lo que su hoja de estilos da a las imágenes en otro lugar, por ejemplo inline cuando no restablece img a block.