92

Dark Mode con Animaciones en CSS y JavaScript

17222Puntos

hace 2 años

¡Te doy la bienvenida a un nuevo reto de CSS! Esta vez vamos a hacer un Toggle Button para cambiar de Light Mode a Dark Mode usando animaciones de CSS y JavaScript.

Compártenos el resultado final en los comentarios y/o en Twitter con el hashtag #RetosPlatziCSS. 😉

0

Antes de comenzar, los cursos de Platzi que te recomiendo para realizar este reto son los siguientes:

Paso 0: planeación

Para este reto te propongo que realices los siguientes 4 pasos:

  1. Crea los estilos base de tu toggle button
  2. Añade JavaScript para crear el movimiento
  3. ¡Pon a prueba tu creatividad! ¡Estiliza tu toggle button!
  4. ¡Compártenos tu resultado en los comentarios!

💡 Recomendación: Evita copiar y pegar el código. Trata de transcribir cada detalle y entender muy bien su funcionamiento (sin afán, tómate tu tiempo). Solo de esta forma podrás convertirte en un(a) experto(a) en maquetación con CSS.

ʕ•́ᴥ•̀ʔっ ¡Empecemos!

Paso 1: crea los estilos base de tu toggle button

Lo primero que tenemos que tener en cuenta es que nuestro botón en realidad será un input de tipo checkbox que nos permitirá hacer el switch entre el modo claro y el modo oscuro. También tendremos un label que estilizaremos a nuestro gusto.

En primera instancia, pensemos que la base fundamental de nuestro toggle button para el modo claro debe verse de la siguiente manera:

1

Y para el modo oscuro debe verse de esta otra forma:

2

Teniendo en cuenta lo anterior, esta es la paleta de colores que en nuestro CSS se vería de la siguiente forma:

:root {
  --light-0: #f8f9fa;
  --light-1: #e9ecef;
  --light-2: #dee2e6;
  --dark-0: #495057;
  --dark-1: #343a40;
  --dark-2: #212529;
}

💡 Tutorial: variables nativas en CSS

Ahora debemos escribir el HTML que nos permitirá tener el input, el label y el div para la bolita del centro:

<input id="toggle-button" type="checkbox">
<labelfor="toggle-button">
  <div class="sun-moon"></div>
</label>

Teniendo nuestro HTML podemos escribir los estilos para nuestro body, tanto para el modo claro como para el modo oscuro.

A nuestro body le quitaremos la margen por defecto (margin: 0) y le añadiremos

  • Background claro (background: var(--light-0)).
  • Centrado de elementos (display: grid y place-items: center).
  • Alto de toda la página que esté visualizando el usuario (height: 100vh).
  • Y una transición al background para cuando hagamos el switch entre el modo claro y oscuro (para que no se vea tan tosco) (transition: background 0.3s ease).
body {
  background: var(--light-0);
  display: grid;
  height: 100vh;
  margin: 0;
  place-items: center;
  transition: background 0.3s ease;
}

A nuestro body también le añadiremos una clase llamada dark que nos permitirá cambiar el background a partir de JavaScript más adelante:

body.dark {
  background: var(--dark-2);
}

Con nuestro body listo comenzamos a estilizar nuestro label para el modo claro. Debemos añadir una posición relativa (position: relative) para que nuestro input se pueda ocultar detrás de él (con position: absolute), también añadimos un background para el modo claro (background: var(--light-2)), un borde redondeado (border-radius: 20px), una manita en el cursor que indique que podemos hacer click allí (cursor: pointer), un alto (height: 38px) y un ancho (width: 68px):

input {
  position: absolute;
}

label {
  background: var(--light-2);
  border-radius: 20px;
  cursor: pointer;
  height: 38px;
  position: relative;
  width: 68px;
}

Y para el modo oscuro del label debemos decirle al input que cuando esté checkeado (#toggle-button:checked) cambie el background de su hermano (+ label):

#toggle-button:checked + label {
  background: var(--dark-0);
}

Ahora podemos crear los estilos para la bolita del centro. Yo voy a añadir un color de fondo (background: var(--light-1)), un ancho (width: 30px) y un alto (height: 30px) con las mismas dimensiones, un redondeado para hacer la forma de un círculo (border-radius: 50%), un margen para que no quede tan cerca a los bordes del label (margin: 4px) y finalmente una transición a la transformación (que hará que se desplace de izquierda a derecha) para cuando hagamos el switch entre el modo claro y oscuro y no se vea tan tosco (transition: transform 0.3s ease):

label.sun-moon {
  background: var(--light-1);
  border-radius: 50%;
  height: 30px;
  margin: 4px;
  transition: transform 0.3s ease;
  width: 30px;
}

Para el modo oscuro de la bolita debemos decirle al input que cuando esté checkeado (#toggle-button:checked) cambie el background (background: var(--dark-1)) y le añada una transformación (transform: translateX(30px)) del hijo de su hermano (+ label .sun-moon):

#toggle-button:checked + label.sun-moon {
  background: var(--dark-1);
  transform: translateX(30px);
}

Paso 2: añade JavaScript para crear el movimiento

Una vez que tenemos los estilos de nuestro toggle button, debemos decirle desde JavaScript que añada la clase dark al body una vez nuestro input este checkeado para obtener el siguiente efecto:

3

Para eso debemos acceder al DOM de la siguiente forma:

const toggleButton = document.getElementById('toggle-button')

Luego le decimos que escuche cuando se haga un cambio en el toggle buttton (es decir, cada vez que se le haga click):

toggleButton.addEventListener('change', () => {
  // Ahorita ponemos código aquí :)
})

Finalmente, cada que suceda ese cambio le agregamos la clase dark solo cuando esté activo el input:

toggleButton.addEventListener('change', () => {
  document.body.classList.toggle('dark')
})

Paso 3: ¡pon a prueba tu creatividad! Estiliza tu toggle button

En este paso quiero que seas muy libre y añadas el estilo que más te guste. Para eso, aquí te comparto varios ejemplos de la comunidad de CodePen para que te inspires:

En mi caso, quise agregar unos GIF’s de fondo, así:

0

Para lograrlo añadí dos colores más (--green y --blue):

:root {
  --light-0: #f8f9fa;
  --light-1: #e9ecef;
  --light-2: #dee2e6;
  --dark-0: #495057;
  --dark-1: #343a40;
  --dark-2: #212529;
  --green: #c3c82c;
  --blue: #2939ff;
}

También hice modificaciones a los backgrounds quitándoles los colores planos y añadiendo los GIFs:

label {
  align-items: center;
  background: var(--light-2);
  background: url('https://i.ibb.co/ZWmbGbj/etmfdr.gif');
  background-position: bottom;
  background-size: cover;
  border-radius: 35px;
  box-shadow: 019px38pxrgba(0,0,0,0.30), 015px12pxrgba(0,0,0,0.22);
  cursor: pointer;
  display: flex;
  height: 60px;
  position: relative;
  width: 110px;
}

#toggle-button:checked + label {
  background: var(--dark-0);
  background: url('https://i.pinimg.com/originals/94/ff/74/94ff7463a1574221ba6d4ada2c997e0b.gif');
  background-position: center;
  background-size: cover;
}

label.sun-moon {
  background: radial-gradient(var(--green), transparent);
  border-radius: 50%;
  height: 30px;
  margin: 4px;
  transition: transform 0.3s ease;
  width: 30px;
}

#toggle-button:checked + label.sun-moon {
  background: radial-gradient(var(--blue), transparent);
  transform: translateX(72px);
}

Paso 4: ¡Compártenos tu resultado en los comentarios!

¡Este paso es mi favorito! Compártenos en los comentarios y/o en Twitter con el hashtag #RetosPlatziCSS el resultado final de tu toggle de light a dark mode. 😄

Aquí te comparto mi codepen, mi repositorio de GitHub y el deploy con el resultado final.

¡Cuéntanos qué otro tipo de retos te gustaría encontrar en esta sección!

#NuncaParesDeAprender

Estefany
Estefany
teffcode

17222Puntos

hace 2 años

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
7
9451Puntos

wow!!! acabo de terminar uno y ya hay otro, excelente!!  🤗

4
17222Puntos
2 años

Esoooo !!! ✨ 🚀 🌚

3
9451Puntos
2 años

reto cumplido! muchas, excelente tuto bien explicado, muchas gracias.

Screen Shot 2022-01-25 at 23.19.39.png
Screen Shot 2022-01-25 at 23.20.01.png
2
17222Puntos
2 años

WOOOOOOOW !!! 🤩 Espectacular es POCO !!! Muchas felicitaciones, te quedó increíble… Fan #1 de este resultadooo 💚

4
8487Puntos
Me encantó el tutorial, aquí están mis resultados:)

day.png

night.png

2
17222Puntos
2 años

Más que espectacular !!! 🤩 Increíble resultado… TOP !!! 💚 Muchas felicitacionesss 👏🏼

3
9412Puntos

Espectacular!!! Voy a intentar integrar el dark mode a mi porafolio para darle un toque mas profesional. Gracias!!!

1
17222Puntos
2 años

Esooo 💚💚💚💚

2
7241Puntos

Me acabas de salvar la vida para un proyecto que ahora mismo estoy llevado acabo! Muchas gracias!

2
62993Puntos
2 años

Que bien Rodrigo 😄
Espero nos compartas tu resultado.

1
17222Puntos
2 años

Yujuuuu 🤩💚

2
22848Puntos

Esto está genial. Aunque todavía no tengo casi conocimientos de animaciones en CSS (pero me estoy haciendo todos los newbie challenges de frontendmentor ^^), voy a guardar este post para resolverlo en un par de semanas cuando tenga los conocimientos…

Gracias por esta oportunidad Teff!

3
22848Puntos
2 años

Not yet, pero calculo en 2 semanas estar ahí 😄. Fantástico! Voy a empezar con el de Transformaciones y Transiciones, quiero hacer que un hover pinte de color una imagen oscura en blur con baja opacidad y aparezca un texto, como flotando…

De hecho me acabas de dar una idea.

A darle! Gracias por todo Teff! You rock!

2
17222Puntos
2 años

Me encanta !!! De unaaa 💪🏼 Me muestras cuando lo hagassss… suena espectacular 🤩

Y, siempre es con el mayor de los gustos 💚

1
19483Puntos

Estuvo genial el tutorial, me ayudo aprender bastante y tener dos trucos super geniales, el “checked” y el valor “change” en un** addEventListener.**.

Quiero compartir mi resultado y que también encontré 2 casos de mejora en el tutorial. El primero es que al meter un div dentro de un label estamos cometiendo un error semántico.

        <input id="toggle-button" type="checkbox">    
        <labelfor="toggle-button">
            <div id="dark-mode"></div>
        </label>

De hecho, si lo verificamos en el validador de HTML de la W3C nos lo dira.

W3C Image

Para solucionar este problema podemos crear un pseudo-elemento before o after de la etiqueta label y colocarle los estilos que le habíamos colocado a nuestro div a este pseudo-elemento. Obtendremos el mismo resultado sin el error de la semántica. Y podemos eliminar el div tranquilamente.

En mi caso, estos fueron los estilos que coloque.

.main-contentlabel::before {
  content: "";
  width: 6rem;
  height: 6rem;
  margin: 0.8rem;
  background: radial-gradient(lightyellow, lightsteelblue);
  border-radius: 50%;
  position: absolute;
  cursor: pointer;
  opacity: 0.3;
  transition: transform 0.5s ease;
}

El segundo caso de mejora tiene que ver con validar que el valor del input check sea true. En mi caso mi tematica fue de Totoro.

Totoro lightTotoro dark
Totoro lightTotoro dark
  • El problema es el siguiente:

Al recargar la página estando en el modo dark el boton se queda en el lado dark, pero con los estilos light.

Totoro error

Lo que hice para solucionarlo fue crear una validación con JavaScript donde si el valor del input check es true (Que está en estado checked) los estilos fueran dark, de lo contrario no se los colocara.

const toggleButtonValue = toggleButton.checked;

toggleButtonValue === true ? mainContent.classList.add("dark"): false;

Posterior coloqué la función para el cambio del modo.

Les dejaré el link a mi ejercicio subido en GitHub pages. Muchas gracias por este tutorial.

Link:https://leandergs.github.io/totoro-dark-mode-button/

1
68880Puntos

Hi everyone. 💚
I love this kind of challenge. This is my project and I hope you like it.
Link of project on Twitter.

3
62993Puntos
2 años

Woooow te quedo genial Ernesto!!!
Si no lo han visto los invito a ver su resultado me encanto 💚

1
17222Puntos
2 años

This is an AMAZING WORK !!! 💚 Contratulations, Ernerdo !!! 🤩 I love it !!!