JS DOM: Falling Snow Effect
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 // 2025-04-30 // copyright 2014, 2025 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 xtotal = 30; const xdrift = 50; const xgravity = 100; const updatefreq = 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 f_randomInt = ( xmin, xmax, ) => (Math.floor(Math.random() * (xmax + 1 - xmin) + xmin)); const f_randomReal = (xmin, xmax) => (Math.random() * (xmax - xmin) + xmin); const f_randomColor = () => ("hsla" + "(" + f_randomInt(0, 360) + "," + f_randomInt(70, 100) + "%," + f_randomInt(40, 60) + "%," + f_randomReal(.8, 1) + ")"); const f_randomRed = () => ("hsla" + "(0," + f_randomInt(70, 100) + "%," + f_randomInt(40, 60) + "%," + f_randomReal(.8, 1) + ")"); const f_restart_heart = (xx) => { xx["xxleft"] = f_randomInt(0, viewSpaceWidth); xx["xxtop"] = f_randomInt(0, viewSpaceHeight) - viewSpaceHeight; xx["xrotate"] = f_randomInt(-150, 150); xx.style.left = xx["xxleft"] + "px"; xx.style.top = xx["xxtop"] + "px"; xx.style.transform = "rotate(" + xx["xrotate"] + "deg)"; }; const heartbox = document.createElement("div"); heartbox.setAttribute("id", "heartbox"); const f_new_heart = () => { const yy = document.createElement("div"); yy.textContent = heartTypes[Math.floor(Math.random() * heartTypes.length)]; yy["xxleft"] = f_randomInt(0, viewSpaceWidth); yy["xxtop"] = -90; yy["xrotate"] = f_randomInt(-150, 150); yy["xsize"] = 10 + f_randomInt(0, 30); yy.style.left = yy["xxleft"] + "px"; yy.style.top = yy["xxtop"] + "px"; yy.style.transform = "rotate(" + yy["xrotate"] + "deg)"; yy.style.color = f_randomRed(); yy.style.fontSize = yy["xsize"] + "px"; yy.style.position = "fixed"; yy.style.zIndex = f_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 < xtotal; i++) { heartbox.appendChild(f_new_heart()); } } document.body.appendChild(heartbox); const heartNodes = Array.from(heartbox.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 xdrift; } else { return -xdrift; } })(); xx["xxtop"] = xx["xxtop"] + ((xx["xsize"] / 20) * xgravity); if (xx["xxtop"] > viewSpaceHeight + viewSpaceHeight / 10) { f_restart_heart(xx); } else { xx["xxtop"] = xx["xxtop"] + xgravity / 10 * f_randomInt(0, 10); } if (xx["xrotate"] !== 0) { xx["xrotate"] = xx["xrotate"] + f_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, updatefreq); }
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: Position Fixed
- For how to change CSS, see: JS DOM: Change CSS
- For how to create HTML element and attached it to page, see: JS DOM: Create and Insert HTML Element
- To find window dimension and view port dimension, see: Find Window Size