Hace algunos años irrumpió con fuerza el dark-mode –modo oscuro–, que parecía originalmente ideado para reducir la fatiga visual del usuario –porque la web, al fin y al cabo, es una red de documentos pensada para leerse sobre pantallas luminosas–, pero rápidamente se volvió muy popular por su sobria estética y elegante frescura. Compañías como Google o Facebook y sistemas operativos como iOS o Android pronto lo adoptaron y la tendencia se expandió ampliamente y pasó a ser un recurso de diseño más.
Y muchos sites –este incluido– tenían su versión dark y el usuario podía escoger la apariencia y todo era genial. Esto supuso algunos retos técnicos, como diseñar una paleta de color lo suficientemente sólida para soportar ambas versiones, o persistir la decisión del usuario, pero era al mismo tiempo excitante.
Para su implementación, lo mejor era aprovechar la cascada –la C de CSS– y
añadir una clase o atributo al elemento raíz, como html o body como
repasamos en el artículo
Cómo crear diferentes themes en css,
pero hoy podemos simplificar esa aproximación gracias a nuevas capacidades del
lenguaje como prefers-color-scheme o color-scheme y la función light-dark.
En las preferencias del sistema o del navegador, el usuario puede elegir entre
lightodarksiendolightel valor por defecto.
prefers-color-scheme
Es una directiva de tipo @media que nos permite conocer la preferencia del
esquema de color del usuario, y podemos por tanto, reaccionar a su valor.
@media (prefers-color-scheme: light) {
:root {
--bg-color: #ffffff;
--front-color: #ff0066;
}
}
@media (prefers-color-scheme: dark) {
:root {
--bg-color: #171115;
--front-color: #ddccbb;
}
}
Podemos ser muy explícitos y asignar valores a las variables para cada versión o declarar un valor por defecto y sobreescribir las variables para su contrario, el resultado es el mismo. Lo importante es tener una paleta de color bien estructurada y que sea fácil de canalizar a través de custom properties y poder reasignarlas para cada variante, esa es la idea, olvidándonos de detectar, guardar y persistir la preferencia del usuario. Además, cualquier cambio en el esquema de color se aplica en tiempo real.
Imágenes
Si tu site es todo texto y elementos vectoriales no habrá piedras en el camino,
pero quizá tengas imágenes que no contrastan bien con ambos fondos. Para estos
casos, es muy útil utilizar picture. Las etiquetas source aceptan el
atributo media, que es igualito a @media de CSS, por lo que puedes seguir
usando prefers-color-scheme así
<source srcset="alternative.png" media="(prefers-color-scheme: dark)" />
Demo
color-scheme
Esta propiedad le indica al navegador el esquema de color para el que está preparado el documento o un elemento concreto, y cómo deben renderizarse los elementos del sistema (formularios, scrollbars, autofill, etc.)
Es interesante porque puedes hacer el control global o muy granular.
:root {
color-scheme: light dark;
}
.element {
color-scheme: light dark;
}
Merece especial atención la keyword only porque sirve para bloquear un
esquema concreto de manera que el navegador no va a cambiarlo.
form {
color-scheme: only dark;
}
Demo
Existe una alternativa a declarar el esquema de color en :root y es hacerlo en
el head del documento con la etiqueta
<meta name="color-scheme" content="dark light" />
Por otro lado, color-scheme se puede combinar con prefers-color-scheme pero
personalmente me gusta más combinarla con la función de color light-dark()
light-dark
Es una función que acepta dos parámetros de tipo color. El color declarado en
primer lugar se aplica si el esquema de color es light o está sin definir y el
segundo si la preferencia es dark.
/* Para que light-dark() funcione correctamente, es necesario declarar previamente color-scheme: light dark */
:root {
color-scheme: light dark;
}
.element {
color: light-dark(cyan, lime);
}
Por supuesto, se puede utilizar en combinación con variables
.element {
color: light-dark(var(--color-light), var(--color-dark));
}
Este enfoque es más directo y explícito que el de prefers-color-scheme, y
además es muy flexible, porque se puede aplicar a cualquier elemento de forma
independiente, y al aceptar cualquier color, podemos crear excepciones
facilmente. Como contra diremos que, aunque tengamos la declaración de las
variables centralizadas en :root vamos a tener la implementación repartida por
el código.
Demo
If()
Si lo piensas light-dark luce como un if/else así que como alternativa
podríamos usar if() aunque como el soporte aún es limitado, no me lo voy a
tomar muy en serio.
Esta función nos permite aplicar un valor u otro en función del resultado de un
test de style, media o feature así que podríamos hacer algo así
.element {
color: if(media(prefers-color-scheme: dark): purple; else: #f06);
}
Parece que es escribir demasiado y que cualquiera de los enfoques anteriores es mejor, pero es muy interesante y potente.
Demo
Conclusión
Como CSS es un lenguaje en construcción, es capaz de adaptarse a nuestras demandas y necesidades con rapidez, lo que en mi opinión, es la clave de su éxito. Qué enfoque utilices dependerá de tus necesidades.
A veces los focos iluminan las características más brillantes, como
view transitions o if() dejando a otras en zona de sombra, pero que pueden
resultar igual o más interesantes. En este caso, color-scheme y light-dark
me parece que resuelven un problema muy complejo de forma muy sencilla.
Por otro lado, aunque sólo hemos hablado de implementar, es esencial planificar y diseñar una paleta que funcione bien, sin esa base, el resultado puede ser inconsistente o caótico.
