¿Cómo crear un tema light y dark para tu web?

En este post te enseñaré a crear temas dark y light para tus sitios web, además con lo que aprendas podrás crear tus propios temas como un modo Halloween o uno de navidad. ¡Comencemos!

Diseño web
Lectura de 8 minutos
4 nov. 2020
¿Cómo crear un tema light y dark para tu web?

En EDteam tenemos la tradición de crear un tema oscuro para la plataforma cada víspera de Halloween. Desde el 2018, año en que me integré al equipo de diseño UI/UX he sido el encargado de realizar dicha acción (y un año tuve que hacerlo tanto para la web como para la ya extinta aplicación que teníamos en ese entonces).

Son muchos los estudiantes que piden la opción de poder elegir el tema oscuro a voluntad y en cualquier época del año, ¿pero por qué hasta la fecha no hemos habilitado esa característica? Existen diversas razones, pero la principal es que, sinceramente, la forma en que se construyeron los temas anteriores no fue la más óptima; tenían muchas malas prácticas y no eran escalables. Lo anterior no era porque se buscaba la salida más fácil, sino que año con año íbamos mejorando en la parte gráfica (hablando en la interfaz del usuario) como en la técnica (refiriéndonos al código que se escribía).

Hubo muchos retos y complicaciones, pero todo eso se convirtió en el tema de Halloween del 2020, que probablemente no lo sabes, pero este realmente es una variación de otro tema (pequeño spoiler 😁).

Para mí es grato compartirte en este artículo el paso a paso y las cosas que debes tener en cuenta en la creación de temas de un sitio web (hablando de la parte del código). Alguna información son tendencias/tips que te puedes encontrar en muchos blogs, pero la mayoría es resultado de mi propia experiencia. Lo único que necesitarás es tener los conocimientos base en CSS y teoría básica del color.

No empieces sin una guía de estilos

Usualmente antes de crear un tema oscuro se suele diseñar primero la versión clara/light, para esto se hace uso de la guía de estilos. Por si no estás familiarizado con este concepto, una guía de estilos es un manual con los criterios y normas necesarias para desarrollar la parte gráfica de un producto digital de alguna marca con el fin de conseguir una interfaz homogénea y coherente.

En dicho manual vienen incluidos los colores. En esta primera parte los colores que nos importan son los de los siguientes elementos:

  • Principal (suele ser el color de la marca)
  • Títulos
  • Contenido (párrafos de texto)
  • Contenido claro (se suele utilizar en subtítulos)
  • Fondo

¿Por qué empezamos específicamente con esto? Porque son los elementos que están presentes en todo tu sitio web sin importar la página, sección o componente en que te encuentres. Además de que son los que cambian cuando creas un tema. Como te comenté, estos colores ya los debes tener definidos en tu guía de estilos (Figma, Adobe Xd, Sketch, etc) y explicar cómo crear una paleta de colores es tema para otro día, de momento el objetivo de este artículo es llevar esa guía a código y posteriormente crear su versión dark.

Supongamos que nuestros colores son los siguientes:

Entonces lo que debemos hacer es pasar los colores a tu proyecto en código y aplicar algunos estilos base. Los estilos para márgenes, paddings y ese tipo de cosas no las pondremos en el código para centrarnos solo en el color.

Variables de color

1/* Los nombres de las variables lo dejo a tu criterio, pero lo recomendable es que sean descriptivos. */
2:root {
3 --main-color : #1083D6;
4 --title-color : #2A3B47;
5 --text-color : #697477;
6 --light-text-color : #A0A7AC;
7 --body-color : #FBFBFE;
8}

Estilos base

1body {
2 background : var(--body-color);
3 color : var(--text-color);
4}
5
6h1, h2, h3, h4, h5, h6 {
7 color : var(--title-color);
8}
9
10a {
11 color : var(--main-color);
12}
13
14.subtitle {
15 color : var(--light-text-color);
16}
17
18.button {
19 background : var(--main-color);
20}

El contenido de nuestro sitio se vería algo así:

De momento la asignación de color se hace con los estilos base que creamos, pero algo muy, pero MUY importante es que si necesitas asignar color directamente desde CSS y ese color necesita cambiar cuando se active un tema, debes usar la variable correspondiente y no un color quemado.

Manejo de color en tema oscuro

Ya tenemos los colores para la versión light, ¿cómo elegimos los colores para la versión dark u otro tema? Si esperabas un truco, técnica o hack déjame decirte que por ahí no va la cosa. Prácticamente debes hacer el mismo proceso que usaste para obtener los colores light, pero hay algunos consejos que te servirán para elegir una paleta de colores oscura.

No utilices colores puros

Se le conoce como colores puros a aquellos que no tienen gris en su "mezcla". Un par de ejemplos son el blanco (#FFFFFF) y negro (#000000), los cuales son una tentación al momento de crear temas oscuros porque uno pensaría que solo es poner el fondo negro y el texto blanco, pero eso está mal por el alto contraste que terminará siendo un dolor de ojos entre el contenido y el fondo.

Lo recomendable es utilizar gris oscuro en lugar de negro y gris claro en lugar del blanco. Puedes tener las variaciones de grises que necesites, como en nuestro caso que tenemos dos colores para el contenido escrito. Si no quieres perder la identidad de tu marca puedes hacer que los grises se acerquen al color principal de tu marca. Mira cómo lo hace Twitter:

En la primera imagen vemos un fondo negro puro y, aunque el texto no es blanco, sigue habiendo un enorme contraste entre contenido-fondo. En la segunda imagen vemos un gris azulado oscuro que no daña la vista, tal vez no es tan oscuro como se acostumbra ver, pero cumple su objetivo.

Desaturación de colores

El color principal suele ser el mismo que el de la marca y casi siempre se diseñan para que funcionen en un fondo blanco, pero al pasar a fondo oscuro el contraste puede ser escaso, principalmente en contenido escrito. Visualmente podemos notar eso, pero como ayuda extra tenemos el inspector de elementos para ver el contraste entre elemento-fondo, que como podemos observar nos dice que no es muy bueno.

¿Cómo solucionamos esto? Aunque te duela, pero debes modificar el color principal, específicamente la saturación y en ocasiones la iluminación, pero el tono seguirá siendo el mismo (si así lo deseas). Puedes usar el sistema de color HSL para realizar los ajustes necesarios. Recuerda que esto es con el fin de obtener mejor contraste, así que si tu color principal funciona en ambos tipos de fondos (que no pasa muy seguido) déjalo tal y como está.

Sombras

La principal utilidad de las sombras en una UI es para crear un pequeño efecto de elevación en ciertos contenedores, así podemos fácilmente detectar qué es contenido y qué es fondo. Un ejemplo perfecto son los cards de cursos en EDteam.

En tema light todo es miel sobre hojuelas, porque un fondo blanco y una sombra negra se llevan muy bien, ¿pero qué sucede en un tema dark? Es obvio que un fondo negro y una sombra negra no tendrán mucho contraste y probablemente se te ocurran dos cosas (que de antemano te digo que ninguna sirven):

  1. Hacer que la sombra sea más intensa que el fondo

    Admito que esto lo intenté varias veces y yo caía en el engañó diciéndome a mí mismo "Por su puesto que esa sombra sí se ve" por el hecho de que el fondo al final de cuentas era un gris oscuro y la sombra un negro puro, pero al menos que alguien perspicaz y con muy buena vista esté en el sitio, tu sombra NO será visible, o por lo menos no para cumplir su objetivo.

  2. Poner una sombra clara (que realmente sería una luz)

    Hacer esto se resume en una interfaz rara. ¿Cuándo has visto que alguien proyecte luz en lugar de sombra? Claro, tendrás un contraste, pero de nuevo no cumple con su objetivo.

¿Cuál es la solución de todo esto? Primero es quitar la sombra, no nos sirve en una tema oscuro y lo segundo es tener un color de fondo distinto en ese tipo de contenedores. Sí, lo sé, no será una elevación como tal, pero recordemos que debemos irnos primero por la usabilidad que por la estética. Más adelante en este artículo te mostraré una forma sencilla de manejar este tipo de cambios.

Bordes

Algunas interfaces suelen tener bordes, estos mismos los puedes seguir utilizando en otro tema si lo deseas, no hay problema, la situación comienza cuando se eliminan pasando de tema light a dark. Recordemos que el borde es parte del modelo de caja, por lo que al eliminarlo, tu contenido gana más espacio para distribuirse (por más pequeño que sea) y eso se traduce a saltos de líneas inesperados en ciertas situaciones.

Con borde de un 1px

Sin bordes (nótese que de 5 líneas pasaron a ser cuatro)

Lo que amerita en este caso es no eliminar los bordes, sino ponerlos del mismo color que el contenedor. Si tienes diferentes estilos de contenedores puede ser tedioso asignar el mismo valor dos veces para diferentes propiedades, entonces si usas SASS puedes crear un mixin que te ayude a agilizar este proceso.

1@mixin set-background-color($color) {
2 background : #{$color};
3 border-color : #{$color};
4}
5
6.container {
7 @include set-background-color(var(--color));
8}

Modular estilos

Tal vez para este punto pensarás "Qué flojera estar controlando los estilos de todos los componentes", pero si desde un inicio tienes todo manejado de forma modular te será sencillo manejar lo que ya tienes y lo que implementarás después. Lo primero que debes hacer es identificar todo aquello que se reutiliza en tu web, de ahí podemos hacer lo que hemos hecho en todo este artículo, que es sobreescribir variables o crear una clase específicamente para ese componente y sobreescribimos sus propiedades. Si es un proyecto nuevo en lo personal manejaría todo por variables.

Un ejemplo son los contenedores en EDteam, que comparten los mismos estilos.

Si manejamos todo por variables nos quedaría algo como lo siguiente (refiriéndonos sólo a los contenedores y no a su contenido)

Light theme

1:root {
2 --container-background : #fff;
3 --container-shadow : 0 1px 4px rgba(146,161,176,.15);
4}
5
6.container {
7 background : var(--container-backgroound);
8 box-shadow : var(--container-shadow)
9}

Dark theme

1// Como los estilos se aplica en .container, no es necesario que haga algo en esa clase
2// Porque todo se aplica desde las mismas variables
3:root {
4 --container-background : #212E36;
5 --container-shadow : none;
6}

Estructura de archivos

En EDteam es bien sabido que usamos SASS para los estilos de la plataforma. Sin contar la guía de estilos (que utiliza SMACSS) todo nuestro código está separado por componentes. La idea de todo lo que te he contado es que sea fácil crear un tema oscuro, pero habrá excepciones donde tendrás que meter a manito algunas líneas de código. Puedes hacerlo en el mismo archivo del componente, pero en lo personal sentí que era mucho código para un solo archivo, por lo que mi solución fue esta estructura:

1- styles/
2 - styles.scss
3 - Importación de cada componente
4 - Importanción del tema dark
5
6 - components/
7 - Archivos SASS de nuestros componentes
8
9 - dark-theme/
10 -_dark-theme.scss
11 - Estilos bases para el tema dark (variables principalmente)
12 - Importación de los componentes dark
13 - components/
14 - Estilos específicos para componentes en su tema dark

Si te fijas todos lo relacionado con el tema dark se puede controlar desde una importación, por si en alguna situación quieres desactivarlo. También podrías separar el tema light, pero por el tamaño de la plataforma sería un trabajo descomunal.

Con todo lo que hemos visto hasta ahora, nuestros colores quedarían así:

Tema light

Tema dark

Se agregaron algunos más para implementarlos en la parte práctica.

Controlar el estado del tema

Bien, ya tenemos nuestros colores elegidos, testeados y aprobados, ahora viene la parte buena y es que el tema dark funcione.

Elegir el tema según el usuario

Cuando nos encontramos una web que permite al usuario cambiar de tema solo vemos la superficie de toda la magia, ¿pero te has preguntado cómo funciona por dentro? No hay una forma exacta, pero todos los caminos son más o menos iguales. Te contaré cómo lo hice yo.

Lo primero es escribir nuestras variables. Por defecto dejaremos el tema light, significa que mediante una clase que agregaremos al body sobreescribiremos las variables del tema por defecto. En este caso usaremos la clase dark-theme.

1// Variables del tema light
2:root {
3 --main-color : #1083D6;
4 --title-color : #2A3B47;
5 --text-color : #697477;
6 --light-text-color : #A0A7AC;
7 --border-color : #EFF3F5;
8 --container-color : #FFFFFF;
9 --body-color : #FBFBFE;
10}
11
12// Variables para el tema dark
13body.dark-theme {
14 --main-color : #52A5E0;
15 --title-color : #EFF3F5;
16 --text-color : #C8CDD0;
17 --light-text-color : #A0A7AC;
18 --border-color : #2A3B47;
19 --container-color : #212E36;
20 --body-color : #192229;
21}

A continuación agregaremos un botón que será el encargado de hacer el cambio entre temas, no importa qué lleve dentro, siempre y cuando tenga un id para acceder a él por JavaScript. Puedes buscar en Codepen cómo la gente decora este tipo botón por si necesitas ideas, para este ejemplo nos limitaremos a algo simple y empezaremos a usar SASS para ahorrar algo de código.

HTML

1<button class="change-theme-button" id="theme-button"></button>

CSS (Sass)

1.change-theme-button {
2 outline : none;
3 color : var(--title-color);
4 background : none;
5 border : none;
6 cursor : pointer;
7
8 &::before {
9 content : '🌞 Tema claro';
10
11 .dark-theme & {
12 content : '🌝 Tema oscuro';
13 }
14 }
15}

Y por último en este apartado, hagamos que realmente funcione. La magia está en agregar o quitar una clase al body, el resto es trabajo de CSS.

JavaScript

1const themeButton = document.getElementById('theme-button')
2const darkTheme = 'dark-theme'
3
4themeButton.addEventListener('click', () => {
5 document.body.classList.toggle(darkTheme)
6})

Elegir tema según el sistema

Esto suena a que es algo muy complejo, pero realmente es más fácil de lo que piensas. Si viste mi curso de CSS Avanzado sabrás que todo se resume a una media query; con prefers-color-scheme podemos detectar el tema que el usuario está usando en su sistema (recibiendo como valores dark y light), así que si nuestra web es light por defecto, pero el tema del usuario es dark, él ya no necesitará realizar el cambio manualmente.

1// Preguntamos qué tema tiene el usuario
2// true = dark
3// false = light
4const userHasDarkTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
5// Preguntamos si el usuario tiene tema dark
6// En caso de que sí, lo activamos
7if (userHasDarkTheme) document.body.classList.add(darkTheme)

Guardar tema elegido

Ya hicimos que el usuario cambie de tema manualmente y que el sistema elija automáticamente, pero pongamos el caso hipotético de que el usuario tenga tema dark en su sistema y él manualmente elige tema light, todo bien la primera vez, pero cuando regrese a nuestro sitio tendrá que hacer el mismo procedimiento, por lo que nuestro último paso es guardar el tema que el usuario haya usado por última vez. El código ya es un poco complicado porque debemos tener en cuenta todo lo que hemos hecho, confío en que los comentarios ayudarán a entender el proceso.

1// Botón para activar el tema
2const themeButton = document.getElementById('theme-button')
3// Nombre de la clase con la que activamos el tema dark
4const darkTheme = 'dark-theme'
5// Tema seleccionado por el usuario anteriormente (si es que lo hizo)
6const selectedTheme = localStorage.getItem('selected-theme')
7// Preguntamos qué tema tiene el usuario en su sistema
8// true = dark
9// false = light
10const userHasDarkTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
11// Obtenemos el tema actual que tiene la interfaz validando la clase dark-theme
12const getCurrentTheme = () => document.body.classList.contains(darkTheme) ? 'dark' : 'light'
13
14// Validamos si el usuario anteriormente elegió un tema
15if (selectedTheme) {
16 // Si se cumple la validación, preguntamos cuál fue el tema para saber si activamos o desactivamos el dark
17 document.body.classList[selectedTheme === 'dark' ? 'add' : 'remove'](darkTheme)
18} else {
19 // Preguntamos si el usuario tiene tema dark en su sistema
20 // En caso de que sí, lo activamos en la interfaz
21 if (userHasDarkTheme) document.body.classList.add(darkTheme)
22}
23
24// Activar/desactivar el tema manualmente con el botón
25themeButton.addEventListener('click', () => {
26 // Agregamos o quitamos el tema dark
27 document.body.classList.toggle(darkTheme)
28 // Guardamos el tema actual que eligió el usuario
29 localStorage.setItem('selected-theme', getCurrentTheme())
30})

Y así es como se crea un tema como todo un master 😎

Realmente espero que este artículo sea de ayuda al momento de que desarrolles tus propios temas. Si te han quedado dudas o quieres aportar al artículo te espero en los comentarios, nos vemos 👋.

Si quieres aprender a hacer hermosa tu web, como lo hicimos en este tutorial, tienes que ver nuestro curso de CSS Avanzando. ¡Corre a ver la primera clase gratis 🎁!

Curso: CSS Avanzado"

Pero antes de que te vayas cuéntame:

¿Qué otros tutoriales de CSS te gustaría ver?

Avatar

Alexis Mora Angulo

@jopzikVer perfil

🌮 Orgulloso nayarita y mexicano 💻 UI/UX y docente en EDteam 🖱 Hago cosas en Codepen 🏃🏾‍♂️ Runner de fin de semana 🌊 #NoTeDetengas

Comentarios de los usuarios

Avatar
Eduardo Chavez

@eduardochavezdorado68084

wooow excelente! articulo

Avatar

Muy buen articulo, lo complicado puede llegar a ser la paleta de colores, pero con las ideas que das se reduce un poco.

JR
José Ruiz

@joseruiz370

Uno de los mejores artículos del blog. Excelente profe Alexis, muy completo! Un saludo desde Perú 💪🏽

Avatar
Jonathan Barahona

@jonathanbarahona

Muchas gracias gran articulo.

Avatar
Abraham López Castañeda

@abrahamlopezcastaneda

Justo me preguntaba porqué no habían habilitado un modo obscuro en EDteam, siendo que se están poniendo de moda. Pero me quedo satisfecho con la explicación, y lo tendré en cuaenta al momento de diseñar mis proyectos. Muchas gracias

Recuerda iniciar sesión para comentar este articulo

Cursos recomendados

CSS Avanzado

CSS Avanzado

Avatar

Alexis Mora Angulo

5

4.9

CSS desde cero (2020)

CSS desde cero (2020)

Avatar

Alvaro Felipe

5

4.9

Diseño UI

Diseño UI

Avatar

Alvaro Felipe

5

4.9