DEV Community

DYLAN VILLARREAL TOSCANO
DYLAN VILLARREAL TOSCANO

Posted on

100 DAYS CSS CHALLENGE: Day #2

Hola Mundo.

El ejercicio del día #2 requirió utilizar animaciones. Las cuales no estoy muy familiarizado. El objetivo de este reto es entender y comprender el mundo que es el CSS.

Day 2

100 DAYS CSS CHALLENGE DAY 2.
Reto día dos

Código base del reto

HTML

<div class="frame">
  <div class="center">
        <p>Happy coding :)</p>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

CSS

// delete the following line if no text is used
// edit the line if you wanna use other fonts
@import url(https://fonts.googleapis.com/css?family=Open+Sans:700,300);

// use only the available space inside the 400x400 frame
.frame {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 400px;
  height: 400px;
  margin-top: -200px;
  margin-left: -200px;
  border-radius: 2px;
    box-shadow: 4px 8px 16px 0 rgba(0,0,0,0.1);
    overflow: hidden;
  background: #fff;
  color: #333;
    font-family: 'Open Sans', Helvetica, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
}

Enter fullscreen mode Exit fullscreen mode

1. Identificar los elementos del reto

Elementos identificados

El elemento cuenta con 4 contenedores.

El contenedor principal sirve para contener 3 contenedores con estilo de líneas.

De igual manera se pueden identificar alrededor de 6 animaciones, 2 animaciones por línea

Después de la transformación

Al momento de darle clic, el primero y última línea se desplazan al centro, después de llegar rotan para quedar en diagonal y formar una X. La línea de en medio se encoge mientras cambia su opacidad.

Una vez toma la forma de X Al darle clic pasa a su forma original de la manera inversa.

2. Maquetación de los elementos

Para el contenedor principal cree un div al cual le asigne un, Id para posteriormente acceder a él mediante JS, la clase btn para aplicar estilos. A sí como él role button que sería el papel que plantea el reto un botón de menú de hamburguesa

Para las líneas les asigné dos clases, una de ellas la comparten esta contaría y la segunda para identificar a cada uno por separado.

<div id="btn-1" class="btn" role="button">
  <div class="line line-1"></div>
  <div class="line line-2"></div>
  <div class="line line-3"></div> 
</div>
Enter fullscreen mode Exit fullscreen mode

3. Estilos básicos.

Para el diseño del contenedor principal. Opte por hacer uso de display flex para facilitar el acomodo de los elementos

Dejo un recurso rápido del uso de flexbox

btn {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: 80px;
  height: 52px;
}

.btn .line {
  background: white;
  width: 80px;
  height: 8px;
  border-radius: 3px;
  box-shadow: 0 0 13px 0 rgba(0, 0, 0, 0.3);
}
.btn:hover {
  cursor: pointer;
}
Enter fullscreen mode Exit fullscreen mode

Resultado de la aplicación de estilos
Resultado de los estilos

4. Animación de entrada

La animación de entrada de la línea 1 y línea 3 se dividen en dos.

  1. Desplazamiento al centro.
  2. Rotación diagonal.

Mientras que la línea 3 escala su tamaño mientras baja su opacidad.

Para realizar esto haré uso de keyframes

De manera resumida, los keyframes nos permite definir estilos de css por frame para la creación de animaciones.

Animación de la línea 1 y 3
Para este caso definí el 70% y 100%. El 0% sería la posición inicial.

  • 70% Traslada en el eje y 21 píxeles.
  • 100% Rota la línea -45 grados y termina de acomodar la linea para centrarla.

En el caso del translate que agregue en el 100% lo hice a ojo mirando que la X que se forma se mirara céntrica.

Para la línea 3 el translareY es negativo, ya que va de abajo hacia arriba.

/* Linea 1 */
@keyframes moveTopToCenter {
  70% {
    transform: translateY(21px);
  }
  100% {
    transform: rotate(-45deg) translateY(17px) translateX(-14px);
  }
}

/* Linea 3 */
@keyframes moveBottomToCenter {
  70% {
    transform: translateY(-21px);
  }
  100% {
    transform: rotate(45deg) translateY(-14px) translateX(-15px);
  }
}
Enter fullscreen mode Exit fullscreen mode

Animación de la línea 3

Para esta línea fue un scale de 1 a 0, agregando opacidad de 0.7 al 50% para evitar que se visualiza muy transparente a la mitad de la animación para al 100% ser de 0

@keyframes reduce {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(0.7);
    opacity: 0.7;
  }
  100% {
    transform: scale(0);
    opacity: 0;
  }
}
Enter fullscreen mode Exit fullscreen mode

Para el manejo de tiempo de animación, cree otra clase llamada animated. La cual uso para aplicarle a todas la misma duración.

.animated {
  animation-duration: 1s;
  animation-fill-mode: both;
}
Enter fullscreen mode Exit fullscreen mode

La idea de hacerlo de est amanera la aprendi de una libreria usada para la creacion de animaciones Animate CSS

Resultado después de la aplicación de los estilos

Forma 100%

Para regresarlas a la forma anterior, aplique lo mismo pero a la inversa.

/* Linea 1 */
@keyframes leaveTopToCenter {
  0% {
    transform: rotate(-45deg) translateY(17px) translateX(-14px);
  }
  30% {
    transform: rotate(0deg) translateY(21px) translateX(0px);
  }
  100% {
    transform: translateY(0);
  }
}

/* Linea 3 */
@keyframes leaveBottomToCenter {
  0% {
    transform: rotate(45deg) translateY(-14px) translateX(-15px);
  }
  30% {
    transform: rotate(0deg) translateY(-21px) translateX(0px);
  }
  100% {
    transform: translateY(0);
  }
}
/* Linea 2 */
@keyframes expand {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}
Enter fullscreen mode Exit fullscreen mode

5. JS para controlar la animación

Esta fue mi propuesta para el código donde al momento de darle clic al botón agrega las clases respectivas apara la transformación.


 const btn1 = document.getElementById("btn-1");
 const lines = document.getElementsByClassName("line");

// Funcion para eliminar y agregar clases a elemetnos html
 const classHelper = (elementHtml, classAdd, classRemove) => {
   elementHtml.classList.add(classAdd);
   elementHtml.classList.remove(classRemove);
 };

// Funcion qencargada de disparar la animacion
 const dispatchAnimation = () => {
   const [line1, line2, line3] = lines;

   if (line1.classList.contains("moveTopToCenter")) {
      classHelper(line1, "leaveTopToCenter", "moveTopToCenter");
      classHelper(line2, "expand", "reduce");
      classHelper(line3, "leaveBottomToCenter", "moveBottomToCenter");

       classHelper(line2, "d-block", "d-none");
        } else {
       classHelper(line1, "moveTopToCenter", "leaveTopToCenter");
       classHelper(line2, "reduce", "expand");
       classHelper(line3, "moveBottomToCenter", "leaveBottomToCenter");
        // Al momento de terminar la animacion principal aplico estilos
        // Para ocultar el linea 2

        setTimeout(() => {
          classHelper(line2, "d-none", "d-block");
        }, 500);
      }
 };

 btn1.addEventListener("click", () => {
   const clasess = btn1.classList;

   // Clase que utiliso para saber si actualmente se encuentra en transicion
   if (clasess.contains("is-animating")) return;

   // Agrego la clase de que se esta animando
   btn1.classList.add("is-animating");

   // Mando a llamar la funcion para aplicar al animacion
   dispatchAnimation();

   // Elimino la clase de que se esta animando.
   setTimeout(() => {
      btn1.classList.remove("is-animating");
     }, 700);
  });
Enter fullscreen mode Exit fullscreen mode

Resultado final

Revisando la manera en que lo realiza la página de 100 días de CSS, a sí como videos de YouTube realizando el mismo ejercicio, encontré puntos de mejora en mi código para hacerlo más legible y óptimo.

Háganme saber en los comentarios si quieren un post analizando los cambios que se pueden aplicar y otras formas de realizar este reto del día dos.

Top comments (0)