Si bien se suele establecer en la raíz, la propiedad color-scheme se puede establecer en elementos individuales para forzarlos a un esquema de colores diferente del resto de la página.
Esto puede ser útil para los componentes que siempre se deben ver en un esquema de colores específico (p.ej., siempre en modo oscuro o claro).
Como ejemplo, se incluyen los siguientes casos prácticos:
- Elementos que suelen estar en modo oscuro incluso en páginas en modo claro por motivos estéticos, p.ej., bloques de código, reproductores multimedia y galerías de fotos
- Las áreas que contienen contenido multimedia diseñado para un fondo claro (p.ej., imágenes, videos, ilustraciones y vistas previas de impresión) se pueden configurar en el modo claro, incluso si el resto de la página está en el modo oscuro.
- Elementos cuyo esquema de colores se controla mediante un parámetro de configuración a nivel del usuario, como las vistas previas de los componentes
- Incrustaciones que no admiten los modos claro y oscuro
- Herramientas de diseño, mapas, visualizaciones, juegos, etcétera
¿Cuándo cambiar los colores y cuándo forzar el color-scheme?
No todos los elementos que usan texto más claro sobre un fondo más oscuro en el modo claro o texto más oscuro sobre un fondo más claro en el modo oscuro necesitan un color-scheme diferente.
Por ejemplo, un botón principal puede renderizarse en azul con texto blanco en el modo claro, pero eso no justifica un color-scheme: dark.
Como regla general, los elementos que usan un color-scheme diferente suelen ser superficies complejas que establecen su propio contexto visual, en lugar de contenedores simples y poco profundos.
Cuando consideres usar un color-scheme diferente en un elemento, pregúntate lo siguiente:
- ¿La IU integrada del navegador que no se personaliza de otra manera (p. ej., controles de formulario, barras de desplazamiento, etc.) debería usar ese esquema de colores o adaptarse al de la página? -> Si es el primer caso, no uses
color-scheme. - ¿Los colores de
light-dark()deberían resolverse como lo hacen para el resto de la página o en función de la anulación? -> Si es el primer caso, no usescolor-scheme. - ¿Los descendientes deberían estar en ese
color-scheme? De lo contrario, no usescolor-scheme.
Implementación básica
Las anulaciones específicas de componentes se suelen usar (aunque no es estrictamente necesario) en páginas que también admiten varios esquemas de colores a través de un color-scheme global.
Para implementar correctamente el modo oscuro en toda la página, consulta Modo oscuro.
Una vez que se haya implementado un color-scheme para toda la página y estés usando tokens de color sensibles a él (p.ej., a través de light-dark()), puedes simplemente establecer color-scheme en componentes específicos para anular el modo de color de ese subárbol:
pre, code, .dark {
color-scheme: dark;
}
Ten en cuenta que, de todos modos, algunos navegadores adaptan automáticamente los componentes a un esquema de colores diferente.
Para forzar el esquema de colores especificado en todos los casos, usa only, es decir, color-scheme: only dark; en lugar de color-scheme: dark;.
Cómo adaptar valores que no son de color
Por el momento, light-dark() solo funciona para los colores.
Prácticas recomendadas
- OBLIGATORIO: No establezcas
color-schemeen elementos sin fondo, ya que eso podría mezclar pares de colores de fondo y de texto de diferentes esquemas de colores, lo que daría como resultado un texto ilegible. - OPCIONAL: Si bien es más fácil reutilizar los mismos pares de colores que el modo oscuro de toda la página, podemos definir pares de colores diferentes para estos componentes. Por ejemplo, es posible que queramos que un componente del modo oscuro que se usa en una página con modo claro sea un poco menos oscuro que cuando se usa el mismo componente del modo oscuro en una página que está en modo oscuro en general.
Problemas conocidos que debes tener en cuenta
Un aspecto importante: Herencia de los colores de light-dark()
light-dark() se resuelve en el momento del valor calculado.
Esto significa que cualquier propiedad <color> heredada que se establezca en un color light-dark() solo pasará uno de los dos colores a sus descendientes, no la expresión light-dark() en sí.
Esto incluye lo siguiente:
- Propiedades de color integradas que se heredan, como
color,accent-color,fill,stroke,text-shadowycaret-color - Cualquier propiedad personalizada heredable registrada con
syntax: <color>yinherits: true - Cualquier otra propiedad
<color>establecida eninherit
Esto significa que debes hacer lo siguiente:
- NO registres propiedades personalizadas destinadas a contener tokens de diseño (p.ej.,
--surface-color) como<color>. Los tokens deben mantener activa su expresiónlight-dark()para que los descendientes puedan volver a resolverlos con uncolor-schemediferente. - Cuando configures
color-schemeen un elemento, vuelve a especificar las propiedades<color>heredadas que se hayan configurado con valoreslight-dark()(directamente o a través de tokens de diseño), incluso si se trata del mismo token de diseño. - NO uses
inheriten las propiedades<color>de los elementos con una anulación decolor-scheme(se puede usar en sus descendientes). - SÍ usa propiedades
<color>registradas para el caso de uso opuesto: cuando quieras tomar una instantánea del color resuelto del elemento superior y evitar que se vuelva a resolver en elcolor-schemedel elemento descendiente. Por ejemplo, capturar el fondo de la página para usarlo en otro lugar. - Si necesitas animar un color, usa una propiedad
<color>registrada en@propertyindependiente en el elemento que se anima (el registro es obligatorio para la interpolación de colores). No se trata de un token de diseño, sino de un objetivo de animación por elemento, por lo que no entra en conflicto con la regla anterior.
Ejemplo:
:root {
--accent-color: light-dark(blue, skyblue);
--surface-color: light-dark(white, #222);
--text-color: light-dark(#111, white);
color-scheme: light dark;
accent-color: var(--accent-color);
color: var(--text-color);
}
body {
/* --surface-color dynamically switches despite being inherited because --surface-color is not registered */
background: var(--surface-color);
}
pre, code {
color-scheme: dark;
background: var(--surface-color);
/* Without this, accent-color would be blue, not skyblue! */
accent-color: var(--accent-color);
/* Without this, text-color would be #111, not white! */
color: var(--text-color);
}
Problemas que debes tener en cuenta cuando usas color-scheme
- Chrome y Firefox respetan
color-schemepara los iframes: renderizan las páginas incorporadas en el esquema de colores correcto y ajustan la consulta de mediosprefers-color-schemede la página incorporada para reflejar elcolor-schemedel contexto de incorporación. Safari no lo hace y resuelveprefers-color-schemesegún la configuración del sistema, incluso dentro de los iframes.- Si controlas tanto el elemento superior como el iframe, pasa el esquema de colores del elemento superior al iframe de forma explícita, a través de un parámetro de URL (
?theme=dark) en el momento de la construcción del iframe o a través depostMessage()(que también te permite reaccionar a los cambios en el tiempo de ejecución). En el iframe, establece una clase en<html>(ocolor-schemeen:root) a partir de ese indicador en lugar de depender deprefers-color-scheme. - Si solo controlas la página incorporada: No hay una forma confiable de detectar el
color-schemedel contexto de incorporación desde el iframe en Safari. Expón un parámetro de tema explícito en tu API de incorporación (p.ej., una cadena de consulta o un protocolopostMessage) y documéntalo para los incorporadores.
- Si controlas tanto el elemento superior como el iframe, pasa el esquema de colores del elemento superior al iframe de forma explícita, a través de un parámetro de URL (
Estrategias de resguardo
Resguardos y compatibilidad de navegadores con color-scheme
La propiedad color-scheme es una mejora progresiva.
Los navegadores que no la admitan ignorarán esta propiedad y usarán su IU predeterminada de modo claro.
Para adaptarte a las preferencias del usuario en navegadores más antiguos, usa las consultas de medios prefers-color-scheme para proporcionar diferentes colores cuando se prefiera el modo oscuro.
- SÍ: Usa la consulta de medios para cambiar las propiedades personalizadas en
:rootohtml - Evita usar la consulta de medios en componentes individuales, a menos que el componente requiera un tipo muy específico de personalización del modo oscuro más allá de los colores.
:root {
/* Define brand colors for each mode */
--color-brand-light: #0056b3;
--color-brand-dark: #00e5ff;
--color-brand: var(--color-brand-light);
/* MANDATORY: Fallback for browsers without light-dark support */
@media (prefers-color-scheme: dark) {
--color-brand: var(--color-brand-dark);
}
/* Ignored in older browsers */
color-scheme: light dark;
}
button.primary {
background-color: var(--color-brand);
}
Resguardos y compatibilidad de navegadores para light-dark()
En el caso de los navegadores que admiten color-scheme, pero aún no light-dark(), las versiones claras y oscuras de los colores se deben definir primero como propiedades personalizadas, y la consulta de medios prefers-color-scheme se debe usar para establecer los colores del modo correspondiente, como en el siguiente ejemplo:
:root {
/* Define browser UI accent color for each mode */
--brand-accent-light: #0056b3;
--brand-accent-dark: #00e5ff;
--accent-color: var(--brand-accent-light);
/* MANDATORY: Fallback for browsers without light-dark support */
@media (prefers-color-scheme: dark) {
--accent-color: var(--brand-accent-dark);
}
/* OPTIONAL: use light-dark() for more control of built-in UI colors */
@supports (color: light-dark(white, black)) {
--accent-color: light-dark(var(--brand-accent-light), var(--brand-accent-dark));
}
/* MANDATORY: Automatically adapt native UI to user system preferences */
color-scheme: light dark;
/* Example inherited color property */
accent-color: var(--accent-color);
}
pre, code {
color-scheme: dark;
/* **Mandatory**: any inherited color properties must be set again, even if to the same design tokens */
accent-color: var(--accent-color);
}