Creación de elementos y sus animaciones aleatorias con Js y Css 3.7.16
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

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.
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 unorientationchange
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 eventotransitionend
que ejecutará una función anónima que contiene otra función —que sí nos interesa— con unthis
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 eventotransitionend
con el cambio detop
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 conthis
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
yleft
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 eease-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.
- Lo primero es anular la animación (provisoriamente) para luego cambiar la posición a
- Para terminar, ponemos los nuevos valores de
left
ytop
. 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.
Como siempre, los comentarios son un buen lugar para demostrar la imaginación.
Autoría

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.