Creating a Snowfall Effect with HTML, CSS, and JavaScript
This tutorial walks through building a realistic snowfall animation on a web page using HTML span elements, CSS radial gradients, and JavaScript classes to generate, style, animate, and recycle thousands of snowflakes with optional swing, speed variations, 3‑D perspective, and performance‑optimized transforms.
Inspired by a design site that added a snow effect, the article shows how to implement a similar effect on any website using only standard web technologies.
First, a simple static snowflake is created with a span element styled by a CSS radial gradient:
.snow {
display: block;
width: 100px;
height: 100px;
background-image: radial-gradient(#fff 0%, rgba(255,255,255,0) 60%);
border-radius: 50%;
}To generate many snowflakes, a Snow class is defined. The constructor initializes properties such as element reference, size, opacity, position, speed, and window dimensions. The init method randomizes size, opacity, and starting coordinates, while setStyle builds the CSS text for each snowflake using template literals.
class Snow {
constructor(opt = {}) {
this.el = null;
this.width = 0;
this.maxWidth = opt.maxWidth || 80;
this.minWidth = opt.minWidth || 2;
this.opacity = 0;
this.x = 0;
this.y = 0;
this.speed = 0;
this.maxSpeed = opt.maxSpeed || 4;
this.minSpeed = opt.minSpeed || 1;
this.windowWidth = window.innerWidth;
this.windowHeight = window.innerHeight;
this.init();
}
init(reset) { /* randomize size, position, speed */ }
setStyle() { /* set CSS with transform */ }
render() { this.el = document.createElement('div'); this.setStyle(); document.body.appendChild(this.el); }
move() { /* update x, y, recycle when out of bounds */ }
}Hundreds of snowflakes are instantiated and rendered:
let snowList = [];
for (let i = 0; i < 100; i++) {
let snow = new Snow();
snow.render();
snowList.push(snow);
}Animation is driven by requestAnimationFrame in a recursive moveSnow function that calls each snowflake’s move method and then schedules the next frame.
function moveSnow() {
window.requestAnimationFrame(() => {
snowList.forEach(item => item.move());
moveSnow();
});
}Several enhancements are added:
Separate horizontal ( sx ) and vertical ( sy ) speeds to reduce the diagonal drift.
Randomly spawn some flakes on the left side so the lower‑left corner isn’t empty.
Introduce “quick” large flakes with increased size, opacity, and speed, and apply a CSS perspective and translate3d for a 3‑D effect.
Implement swinging motion using a sine function, with optional swing range limited to 0.9π–1.1π for subtle side‑to‑side movement.
Adjust vertical speed with a cosine curve to make the descent start slow and accelerate.
Set a very high z-index and pointer-events: none so snowflakes stay on top without blocking page interaction.
Use CSS transform: translate(...) instead of left/top for smoother, GPU‑accelerated animation.
The article also shows how to adapt the same framework for rain by shrinking the width to 1 px, removing swing, and rotating each raindrop according to its velocity vector using an atan calculation.
Finally, it suggests combining snow and rain for a sleet effect and optionally tying the animation to real‑time weather data via an API, completing an immersive weather overlay.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.