soy Kseso y esto EsCSS

Creación de elementos y sus animaciones aleatorias con Js y Css

O el conocido efecto vintage Nieve cayendo por el documento remozado, actualizado y puesto al día por Furoya. Ahora con animación CSS, y todavía algo de JS.

Creación de elementos y sus animaciones aleatorias con Js y Css

✎ 0
COLABORACIÓN AUTOR INVITADO
Creación de elementos y animaciones aleatorias con Js y Css

O el conocido efecto vintage Nieve cayendo por el documento remozado, actualizado y puesto al día. Ahora con animación CSS, y todavía algo de JS.

El efecto que vamos a ver a continuación es muy antiguo y muy conocido. Se hacía todo en javascript, porque una década y media atrás no existía el CSS transition. Hoy es un poco más fácil y por eso es la excusa de este artículo.

En el hemisferio sur ya es invierno, pero como en la ciudad donde vivo no nieva, se me ocurrió hacer el efecto en javascript y CSS para sentarme un rato a mirar el paisaje nevado que no encuentro desde la ventana. Y lo comparto con ustedes.

Ver el pen Falling snow. de Furoya (@solipsistacp) en CodePen.

Nota: El poema Boule de neige de OuLiPo está añadido para simular una página cuya altura es mayor que el viewport para forzar la aparición del scroll.

Detalles y código del invierno virtual.

Comencemos con la idea general.

La página es una común y corriente. Para el caso metí una imagen de fondo al comienzo (gentileza de The British Library) y se puede desplazar para ver el contenido siguiente.

La nieve se mueve en una capa fija por delante del documento. Es transparente al click asi que será sólo visual, y si molesta la podemos hacer desaparecer al bajar el escrol o al imprimir. La capa está en el código fuente, pero los copos de nieve los agregamos con javascript. Ya sabemos cómo se crean elementos al vuelo, y acá ponemos dentro tantos como copos querramos ver.

Para dar la ilusión de que caen del cielo simplemente los creamos un poco más arriba del borde de la capa, y con una transición CSS los desplazamos hacia abajo (y hacia un lado) hasta un poco más lejos del borde inferior, para que se pierdan de vista antes de desaparecer y reaparecer arriba para caer de nuevo como si fuese otro copo.

Para quien conoce de CSS pero no ha seguido los artículos de JS en el blog, hay algo en esta historia que no le va a cerrar: ¿si estamos usando transition, cómo iniciamos la animación sin un cambio de estado en alguna parte de la página?.

Lo típico es que se disparen con un hover, un focus o alguno similar; pero resulta que si tienen una posición y se la cambiamos con javascript, el CSS detecta el nuevo valor y comienza la transición automaticamente.

Claro que una vez terminada, se va a detener. ¿Y cómo hacemos que se repita ciclicamente?.

Con un evento para transiciones ya presentado en este blog : el transitionend que va a ejecutar otra vez su función para recomenzar la caída infinitamente.

El movimento aleatorio se crea con Math.random(), huelga decir; así que con todas las piezas conocidas les presento el código JS y después vamos a los detalles de construcción.

<script type="text/javascript"> onload = inicia; //EJECUTA LA FUNCIÓN AL CARGARSE LA PÁGINA var cantidadCopos = 30; //TOTAL DE COPOS A CREAR function inicia() { /*CREA COPOS CLASE .nieve EN #capa*/ for(c=0; c<cantidadCopos; c++) { copo = document.createElement("div"); copo.setAttribute("class", "nieve"); document.getElementById("capa").appendChild(copo); } /*AGREGA A LOS COPOS UN ESCUCHADOR DE EVENTOS*/ for(n=0; n<cantidadCopos; n++) { document.querySelectorAll("#capa .nieve")[n].addEventListener("transitionend", function(){caida(this)}, false); //document.querySelectorAll("#capa .nieve")[n].innerHTML = n; } /*ASIGNA ESTILOS INICIALES A CADA UNO CON DEMORA DE 15ms*/ setTimeout(function(){ for(c=0; c<cantidadCopos; c++) { elCopo = document.querySelectorAll("#capa .nieve")[c]; /*POSICIÓN HORIZONTAL AL AZAR PARA INICIO*/ elCopo.style.left = Math.floor(Math.random()*100)+ "vw"; /*TRANSICIÓN COMO "CEBADOR"*/ elCopo.style.transition = "top 15ms linear"; /*NUEVA POSICIÓN VERTICAL AÚN OCULTA*/ elCopo.style.top = elCopo.style.top = "1vh"; } }, 15); } /*FUNCIÓN QUE SE REPITE PARA CADA COPO*/ function caida(T) { /*REMUEVE TRANSICIÓN*/ T.style.transition = ""; /*VUELVE AL COPO ARRIBA*/ T.style.top = "0"; /*REASIGNA LA TRANSICIÓN LUEGO DE 15ms*/ setTimeout(function(){ /*VALORES DE PROPIEDAD*/ T.style.transitionProperty = "left, top"; /*DEMORA LA CAÍDA DEL COPO ENTRE 0 Y 3s*/ T.style.transitionDelay = Math.floor(Math.random()*3000)+ "ms"; /*ASIGNA UNA DURACIÓN DE CAÍDA ENTRE 5s Y 20s*/ T.style.transitionDuration = (Math.floor(Math.random()*15000) + 5000)+ "ms"; /*TIPO DE MOVIMIENTO*/ T.style.transitionTimingFunction = "ease-in, ease-out"; /*ASIGNA UNA NUEVA POSICIÓN HORIZONTAL AL AZAR COMO DESTINO*/ T.style.left = Math.floor(Math.random()*100)+ "vw"; /*ASIGNA LA POSICIÓN VERTICAL DE DESTINO POR DEBAJO DE BASE DE CAPA*/ T.style.top = "110vh"; }, 15); } </script>

Como ven, no es complicado; pero se asignan y recontra-asignan valores todo el tiempo. Vamos ahora a los detalles.

  • Empezamos con un evento que inicia la toma de medidas cuando se carga el documento. Como el efecto depende mucho del tamaño de la ventana, convendría agregar un onresize, o un orientationchange o cada evento propietario según el navegador para cuando cambia las medidas del viewport.
    Luego tenemos una variable donde ponemos la cantidad de copos de nieve que mejor se vean en el diseño.
  • La función inicia() crea esa cantidad de <div class="nieve"> dentro de la capa fija que está por delante del documento. Inmediatamente después los recorre con otro bucle para asignarles un escuchador del evento transitionend que ejecutará una función anónima que contiene otra función —que sí nos interesa— con un this que refiere a cada elemento cuando termine su transición. El mecanismo lo estoy resumiendo mucho porque no es más que un ayudamemoria, en realidad ya lo habíamos explicado antes.
  • Las siguientes líneas están dentro de un setTimeout para darle un tiempo al navegador a hacer todos los cambios antes de la asignación inline de los estilos que estamos modificando. El bucle vuelve a recorrer todos los copos para asignar a cada uno su posición horizontal aleatoria dentro del ancho disponible; además de una transición muy rápida que solamente va a servir para forzar el disparo de su evento transitionend con el cambio de top de la siguiente línea. Todo esto ni se ve, no es más que para comenzar la repetición cíclica de la función que está más abajo. Una especie de "cebador".
  • Ahora ya no hay que recorrer los div's con un bucle. Cada uno tiene una llamada a función con this y ésta cambia los formatos de posición "on demand":
    • Lo primero es anular la animación (provisoriamente) para luego cambiar la posición a top:0 y que quede arriba en la capa fuera de la vista (recordemos que está subida -10vh y tiene una altura de 120vh).
    • Otra vez previendo demoras del navegador usamos un setTimeout de apenas 15ms para reescribir los estilos de este copo.
    • Y otra vez ponemos una transición para top y left con un retraso al azar de hasta 3 segundos y una duración del recorrido entre 5 y 20 segundos. Este último cálculo se hace entre 0 y 15; pero al sumarle después 5 nos aseguramos de que la caída no sea ni tan rápida ni tan lerda.
    • La curva de movimiento es ease-in para la horizontal e ease-out para la vertical. Se pueden usar curvas bezier y hasta con valores aleatorios en sus cuatro puntos para hacer más caprichoso el movimiento de los copos, pero esto va en gustos.
  • Para terminar, ponemos los nuevos valores de left y top. El primero será otra vez aleatorio, y la animación va a tomar el punto al azar que tenía como inicio y este nuevo —seguramente con otras coordenadas, por azar— como destino en horizontal. El segundo valor siempre comienza en 0 y termina en 110vh vertical; es el que realmente da la ilusión de "caída", que entonces combinado con el horizontal parece "arrastrado por el viento".

Las cuatro estaciones animadas.

La nieve no es el único diseño que puede usar el efecto. Seguramente todos hemos visto la versión de las hojas secas para el otoño, y alguna vez hice una de movimiento horizontal para unas mariposas en primavera, o de luciérnagas para el verano. Éstas ya no atravesaban la pantalla, sino que se movían libremente en un impredecible "zig-zag". Para hacerlo hoy quizá sería mejor usar keyframes, ya probé hacerlo con CSS puro y funcionó bastante bien.

See the Pen Image with random flight. Pure CSS. by solipsistaCP (@solipsistacp) on CodePen.


Como siempre, los comentarios son un buen lugar para demostrar la imaginación.

Autoría

Furoya: Autor del artículo

Artículo original de Furoya.
La intención del autor con sus colaboraciones no es que los artículos sirvan para hacer un copy&paste de códigos sino que comprendas y aprendas la lógica y el cómo trabaja javaScript.
Y a partir de lo expuesto experimentes tú.
El autor del post y el editor del blog te animamos a que plantees tus dudas o reflexiones y que compartas tus realizaciones en base a lo expuesto en los comentarios. Recuerda que puedes incluir pens (ejemplos en Codepen.io) en ellos.