Recreando la animación de Porky Pig de Looney Tunes en CSS

Ya sabes, Porky Pig saliendo de esos anillos rojos que anuncian el final de una caricatura de Looney Tunes. Llegaremos allí, pero primero debemos cubrir algunos conceptos de CSS.

Todo en CSS es un cuadro o rectángulo. Los rectángulos se apilan y se pueden mostrar encima o debajo de otros rectángulos. Los rectángulos pueden contener otros rectángulos y usted puede diseñarlos de manera que el rectángulo interior sea visible fuera del rectángulo exterior (para que se desborden) o queden recortados por el rectángulo exterior (usando overflow: hidden). Hasta ahora, todo bien.

¿Qué sucede si deseas que un rectángulo sea visible fuera del rectángulo que lo rodea, pero solo en un lado? Eso no es posible, ¿verdad?

Quizás, cuando miras la imagen de arriba, las ruedas comienzan a girar: ¿Qué pasa si copio el rectángulo interior, recorto la mitad y luego lo coloco exactamente? . Pero cuando se trata de eso, no puedes elegir que un elemento se desborde en la parte superior sino que se recorte en la parte inferior.

¿O puedes?

transformaciones 3D

transformaciones 3D puedes rotar, transformar y usar elementos en el espacio 3D. Aquí hay un grupo de ejemplos prácticos que reúnen y que muestran algunas posibilidades.

Para que las transformaciones 3D funcionen, necesitas dos propiedades CSS:

  • perspective, utilizando un valor en píxeles, para determinar qué tan pronunciado es el efecto 3D
  • transform-style: preserve-3d, para decirle al navegador que mantenga los elementos posicionados en el espacio 3D.

Incluso con el buen soporte que tienen las transformaciones 3D, lamentablemente no se ven muchas las transformaciones 3D “en la naturaleza”. Los sitios web siguen siendo algo “2D”, una página plana que se desplaza. Pero cuando comencé a jugar con transformaciones 3D y a explorar ejemplos, encontré uno que era, con diferencia, el más interesante en lo que respeta a transformaciones 3D:

La imagen muestra claramente tres aviones pero este efecto se consigue utilizando uno solo div. Los otros dos planos son los pseudoelementos y que se mueven hacia arriba y hacia abajo respectivamente, usando ::before, para apilarse uno encima del otro en el espacio 3D. Lo que se nota aquí es cómo el elemento, que normalmente estaría colocado encima de un elemento, está detrás de ese elemento. El creador pudo lograr esto agregando.::aftertranslate()::aftertransform: translateZ(-1px);

Aunque esta fue una de las muchas transformaciones 3D que había visto hasta este momento, fue la primera que me hizo darme cuenta de que en realidad estaba posicionando elementos en el espacio 3D. Y si puedo hacer eso, también puedo hacer que los elementos se crucen:

No podía pensar en cómo sería útil este tipo de cosas, pero luego vi la animación de dibujos animados de Porky Pig. Él emerge de detrás del marco inferior, pero su cara se superpone y se apila en la parte superior del borde superior del mismo marco, exactamente el mismo tipo de situación de recorte que vimos antes. Fue entonces cuando mis ruedas empezaron a girar. ¿Podría replicar ese efecto usando solo CSS? Y para obtener crédito adicional, ¿podría replicarlo usando un solo div?

Empecé a jugar y relativamente rápido obtuve esto como prueba:

Aquí tenemos un single divcon sus pseudoelementos ::beforey un . ::afterEl div en sí es transparente, ::beforetiene un borde azul y ::afterha sido girado a lo largo del eje x. Debido a que el div tiene perspective, todo está posicionado en 3D y, por eso, el ::afterpseudoelemento está encima del borde en el borde superior del marco y detrás del borde en el borde inferior del marco.

Aquí está eso en código:

div {  transform: perspective(3000px);  transform-style: preserve-3d;  position: relative;  width: 200px;  height: 200px;}div::before {  content: "";  width: 100%;  height: 100%;  border:10px solid darkblue;}div::after {  content: "";  position: absolute;  background: orangered;  width: 80%;  height: 150%;  display: block;  left: 10%;  bottom: -25%;  transform: rotateX(-10deg);}

Con perspective, podemos determinar qué tan lejos está un espectador de “z=0”, que podemos considerar como el “horizonte” de nuestro espacio CSS 3D. Cuanto mayor sea la perspectiva, menos pronunciado será el efecto 3D y viceversa. Para la mayoría de las escenas 3D, un perspectivevalor entre 500 y 1000 píxeles funciona mejor, aunque puedes jugar con él para obtener el efecto exacto que deseas. Puedes comparar esto con el dibujo en perspectiva: si dibujas dos puntos del horizonte juntos, obtienes una perspectiva muy fuerte; pero si están muy separados, las cosas parecen más planas.

De rectángulos a dibujos animados

Los rectángulos son divertidos, pero lo que realmente quería construir era algo como esto:

No pude encontrar ni crear una versión bien recortada de Porky Pig a partir de esa imagen, pero la página de Wikipedia contiene una buena alternativa, así que la usaremos.

Primero, necesitamos dividir la imagen en tres partes:

  • div: el fondo azul detrás de Porky
  • ::after: todos los círculos rojos que forman una especie de túnel
  • ::before: El propio Porky Pig en todo su esplendor, como imagen de fondo

Empezaremos con el div. Ese será el fondo además de la base para el resto de elementos. También contendrá las propiedades perspectivey transform-styleque mencioné anteriormente, junto con algunos tamaños y el color de fondo:

div {  transform: perspective(3000px);  transform-style:preserve-3d;  position: relative;  width: 200px;  height: 200px;  background: #4992AD;}

Muy bien, a continuación, pasaremos a los círculos rojos. El elemento en sí tiene que ser transparente porque esa es la apertura por donde emerge Porky. Entonces, ¿cómo lo haremos? Podemos usar un borde como en el ejemplo anterior de este artículo, pero solo tenemos un borde y puede tener un color sólido. Necesitamos un montón de círculos que puedan aceptar gradientes. En su lugar, podemos usar box-shadowencadenar múltiples sombras en los valores de propiedad. Esto nos proporciona todos los círculos que necesitamos y, al utilizar un valor de radio de desenfoque 0con una radio de extensión grande, podemos crear la apariencia de múltiples “bordes”.

box-shadow: x-offset y-offset blur-radius spread-radius color;

Usaremos un border-radiusque sea tan grande como él divmismo, formando ::beforeun círculo. Luego agregaremos las sombras. Cuando agregamos algunos círculos rojos con una gran extensión y agregamos blanco borroso, obtenemos un efecto que se parece mucho al túnel de Porky.

box-shadow: 0 0 20px   0px #fff, 0 0 0  30px #CF331F,            0 0 20px  30px #fff, 0 0 0  60px #CF331F,            0 0 20px  60px #fff, 0 0 0  90px #CF331F,            0 0 20px  90px #fff, 0 0 0 120px #CF331F,            0 0 20px 120px #fff, 0 0 0 150px #CF331F;

Aquí, agregamos cinco círculos, cada uno de los cuales es 30pxancho. Cada círculo tiene un fondo rojo sólido. Y, al usar sombras blancas con un radio de desenfoque de 20pxencima, creamos el efecto de degradado.

Con el fondo y los círculos ordenados, ahora agregaremos Porky. Comencemos agregándolo en el lugar donde queremos que termine, por ahora encima de los círculos.

div::before {  position: absolute;  content: "";  width: 80%;  height: 150%;  display: block;  left: 10%;  bottom: -12%;  background: url("Porky_Pig.svg") no-repeat center/contain;}

Es posible que hayas notado la barra diagonal en " center/contain" para el archivo background. Esa es la sintaxis para establecer tanto la posición ( center) como el tamaño ( contain) en la backgroundpropiedad CSS abreviada. La sintaxis de barra diagonal también se usa en la fontpropiedad CSS abreviada donde se usa para establecer font-sizey line-heightasí: font-size/line-height.

La sintaxis de barra diagonal se utilizará más en futuras versiones de CSS. Por ejemplo, la sintaxis actualizada rgb()y hsl()de color puede tomar una barra seguida de un número para indicar la opacidad, así: rgb(0 0 0 / 0.5). De esa manera, no es necesario cambiar entre rgb()y rgba(). Esto ya funciona en todos los navegadores, excepto Internet Explorer 11.

Tanto el tamaño como la posición aquí son un poco arbitrarios, así que juega con eso como mejor te parezca. Estamos mucho más cerca de lo que queremos, pero ahora necesitamos conseguirlo para que la parte inferior de Porky quede detrás de los círculos rojos y su mitad superior permanezca visible.

El truco

Necesitamos transponer tanto los círculos como a Porky al espacio 3D. Si queremos rotar a Porky, hay algunos requisitos que debemos cumplir:

  • No debe atravesar el fondo.
  • No debemos rotarlo tanto que la imagen se distorsione.
  • La parte inferior de su cuerpo debe estar debajo de los círculos rojos y la parte superior de su cuerpo debe estar por encima de ellos.

Para asegurarnos de que Porky no atraviese el fondo, primero movemos los círculos en la dirección Z para que aparezcan más cerca del espectador. Porque preserve-3dse aplica significa que también se acercan un poco, pero si solo los movemos un poquito, el efecto de zoom no se nota y terminamos con suficiente espacio entre el fondo y los círculos:

transform: translateZ(20px);

Ahora Porky. Vamos a rotarlo alrededor del eje X, haciendo que la parte superior de su cuerpo se acerque a nosotros y la parte inferior se aleje. Podemos hacer esto con:

transform: rotateX(-10deg);

Esto parece bastante malo al principio. Porky está parcialmente escondido detrás del fondo azul, y también está recortando los círculos de una manera extraña.

Podemos resolver esto acercando a Porky a nosotros (como hicimos con los círculos) usando translateZ(), pero una mejor solución es cambiar la posición de nuestro punto de rotación. En este momento ocurre desde el centro de la imagen, lo que hace que la mitad inferior de la imagen gire alejándose de nosotros.

Si movemos el punto inicial de la rotación hacia la parte inferior de la imagen, o incluso un poco más abajo, entonces la totalidad de la imagen gira hacia nosotros. Y como ya acercamos los círculos a nosotros, todo termina luciendo como debería:

transform: rotateX(-10deg);transform-origin: center 120%;

Para tener una idea de cómo funciona todo en 3D, haga clic en "mostrar depuración" en el siguiente lápiz:

Animación

Si mantenemos las cosas como están (una imagen estática), entonces no habríamos tenido que pasar por todos estos problemas. Pero cuando animamos cosas, podemos revelar las capas y mejorar el efecto.

Esta es la animación que busco: Porky comienza pequeño en la parte inferior detrás de los círculos, luego se acerca y emerge del fondo azul sobre los círculos rojos. Se queda allí un rato y luego vuelve a salir.

Lo usaremos transformpara que la animación obtenga el mejor rendimiento. Y debido a que estamos haciendo eso, debemos asegurarnos de mantenerlo rotateXahí también.

@keyframes zoom {  0% {    transform: rotateX(-10deg) scale(0.66);  }  40% {    transform: rotateX(-10deg) scale(1);  }  60% {    transform: rotateX(-10deg) scale(1);  }  100% {    transform: rotateX(-10deg) scale(0.66);  }}

Pronto podremos configurar diferentes transformaciones directamente, ya que los navegadores han comenzado a implementarlas como propiedades CSS individuales. Eso significa que repetir eso rotateX(-10deg)eventualmente será innecesario; pero por ahora tenemos un poco de duplicación.

Nos acercamos y alejamos usando la scale()función y, debido a que ya hemos configurado un transform-origin, la escala se realiza desde el centro-inferior de la imagen, ¡que es precisamente el efecto que queremos! Estamos animando la escala hasta el 60% del tamaño real de Porky, tenemos un pequeño descanso en el punto más grande, donde sale completamente del marco del círculo.

La animación continúa en el ::beforepseudoelemento. Para que la animación parezca un poco más natural, utilizamos una ease-in-outfunción de sincronización, que ralentiza la animación al principio y al final.

div::before {  animation-name: zoom;  animation-duration: 4s;  animation-iteration-count: infinite;  animation-fill-mode:forwards;  animation-timing-function: ease-in-out;}

¿Qué pasa con el movimiento reducido?

¡Me alegra que hayas preguntado! Para las personas que son sensibles a las animaciones y prefieren un movimiento reducido o nulo, podemos recurrir a la prefers-reduced-motionconsulta de medios. En lugar de eliminar la animación completa, nos centraremos en aquellos que prefieren el movimiento reducido y utilizaremos un efecto de desvanecimiento más sutil en lugar de la animación completa.

@media (prefers-reduced-motion: reduce) {   @keyframes zoom {    0% {      opacity:0;    }    100% {      opacity: 1;    }  }  div::before {    animation-iteration-count: 1;  }}

Al sobrescribir el @keyframesinterior de una consulta de medios, el navegador la seleccionará automáticamente. De esta manera, todavía acentuamos el efecto de Porky saliendo de los círculos. Y al configurarlo animation-iteration-counten 1, todavía permitimos que las personas vean el efecto, pero luego nos detenemos para evitar el movimiento continuo.

Últimos retoques

Dos cosas más que podemos hacer para que esto sea un poco más divertido:

  • Podemos crear más profundidad en la imagen agregando una sombra detrás de Porky que crece a medida que emerge y parece acercarse a la vista.
  • Podemos girar a Porky mientras se mueve, para embellecer aún más el efecto emergente.

Esa segunda parte la podemos implementar usando rotateZ()en la misma animación. Muy facil.

Pero la primera parte requiere un truco adicional. Debido a que usamos una imagen para Porky, no podemos usarla box-shadowporque eso crea una sombra alrededor del cuadro del ::beforepseudoelemento en lugar de alrededor de la forma de Porky Pig.

Ahí es donde filter: drop-shadow()viene al rescate. Mira las partes opacas del elemento y le agrega una sombra en lugar de alrededor del cuadro.

@keyframes zoom {  0% {    transform: rotateX(-10deg) scale(0.66);    filter: drop-shadow(-5px 5px 5px rgba(0,0,0,0));  }  40% {    transform: rotateZ(-10deg) rotateX(-10deg) scale(1);    filter: drop-shadow(-10px 10px 10px rgba(0,0,0,0.5));  }  60% {    transform: rotateZ(-10deg) rotateX(-10deg) scale(1);    filter: drop-shadow(-10px 10px 10px rgba(0,0,0,0.5));  }  100% {    transform: rotateX(-10deg) scale(0.66);    filter: drop-shadow(-5px 5px 5px rgba(0,0,0,0));  }}

Y así fue como recreé la animación de Porky Pig de los Looney Tunes. Todo lo que puedo decir ahora es: “¡Eso es todo, amigos!”.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir