JS: Raining Hearts
This page shows you how to use JavaScript to create a “raining hearts” or “falling snow” effect.
Here is the JavaScript code:
// 2014-08-18 // 2019-09-30 // copyright 2014, 2019-09-30 Xah Lee // feel free to use, but must give credit, link back to this page // from http://xahlee.info/js/js_raining_hearts.html { const num_of_hearts = 30; const driftX = 50; const gravity = 100; const update_speed = 900; // millisecond // const heartTypes= [... "♥💕💓💔💖💗💘💝💞💟💙💚💛💜" ]; const heartTypes= [... "💔♥" ]; const viewportWidth = document.documentElement.clientWidth; const viewportHeight = document.documentElement.clientHeight; const viewSpaceWidth = viewportWidth+50; const viewSpaceHeight = viewportHeight+50; const randomInt = ((xmin,xmax) => (Math.floor( Math.random() * (xmax + 1 - xmin) + xmin ))); const randomReal = ((xmin,xmax) => ( Math.random() * (xmax - xmin) + xmin )); const randomColor = (() => ("hsla" + "(" + randomInt(0,360) + "," + randomInt(70,100) + "%," + randomInt(40,60) + "%," + randomReal(.8,1) + ")" ) ); const f_restart_heart = ((xx) => { xx["xxleft"]=randomInt(0, viewSpaceWidth); xx.style.left= xx["xxleft"] + "px"; xx["xxtop"]=randomInt(0, viewSpaceHeight) - viewSpaceHeight; xx.style.top= xx["xxtop"] + "px"; xx["xrotate"] = randomInt(-150, 150); xx.style.transform = "rotate(" + xx["xrotate"] + "deg)"; }); const heart_box = document.createElement("div"); heart_box.setAttribute("id","heart_box"); const f_new_heart = (() => { const yy = document.createElement("div"); yy. textContent= heartTypes[Math.floor( Math.random() * heartTypes.length )]; yy["xxleft"]=randomInt(0, viewSpaceWidth); yy.style.left= yy["xxleft"] + "px"; yy["xxtop"]= -90; yy.style.top= yy["xxtop"] + "px"; yy["xrotate"] = randomInt(-150, 150); yy.style.transform = "rotate(" + yy["xrotate"] + "deg)"; yy.style.color = randomColor(); yy["xsize"]= 10 + randomInt(0,30); yy.style.fontSize = yy["xsize"] + "px"; yy.style.position="fixed"; yy.style.zIndex= randomInt(100,9999) .toString(); yy.style.transition= "top linear 1.5s, left linear 1.5s, transform linear 1.5s"; // f_restart_heart(yy); return yy; }); { for (let i=0; i < num_of_hearts; i++) { heart_box.appendChild( f_new_heart()) } } ; document.body.appendChild(heart_box); const heartNodes = Array.from (heart_box.children); const f_update_positions = (() => { heartNodes.forEach (((xx: HTMLElement) => { xx["xxleft"] += (() => { const rnd = Math.random(); if ( rnd < 0.3333 ) { return 0; } else if ( rnd < 0.6666) { return driftX;} else { return - driftX; } }) (); xx["xxtop"] = xx["xxtop"] + ( (xx["xsize"]/20) * (gravity) ); if ( xx["xxtop"] > (viewSpaceHeight) + viewSpaceHeight/10 ) { f_restart_heart(xx); } else { xx["xxtop"] = xx["xxtop"] + gravity /10 * randomInt(0,10); }; if ( xx["xrotate"] !== 0 ) { xx["xrotate"] = xx["xrotate"] + randomInt(-30,60); xx.style.transform = "rotate(" + xx["xrotate"] + "deg)"; }; xx.style.left = xx["xxleft"] + "px"; xx.style.top = xx["xxtop"] + "px"; })) }); setInterval( f_update_positions , update_speed); } ;
How Does it Work?
The main thing is to create HTML elements with CSS that's fixed position with respect to window. Each element is a “heart” in its own layer. Then, just create a loop to update the element's positions.
- For how CSS fixed position work, see: CSS: Fix Element to Window (position:fixed)
- For how to change CSS, see: JS: Change CSS
- For how to create HTML element and attached it to page, see: JS: Create and Insert HTML Element
- To find window dimension and view port dimension, see: Find Window Size