How to Create Snow With JavaScript

Adding a snowfall animation to your website is a delightful way to give it a touch of seasonal charm. The following JavaScript example demonstrates how to simulate gently falling snowflakes using only plain HTML, CSS, and JavaScript with no external libraries required.
Snowfall v1.0.1Last Update: May 11, 2026
In this demo, we've attached snowfall to the body of this page. It's snowing!
The script dynamically creates small white circles that drift downward across the screen with a natural, swaying motion. You can easily control the number of snowflakes, their speed, size, and movement patterns for a subtle or festive effect. Once you’ve placed this code into your page, it immediately begins animating snow across the viewport.
Snowfall JavaScript
Enter the following JavaScript in a file snowfall.js
/* Snowfall — drop this script anywhere in your page to add full-screen falling snow */
(() => {
const COUNT = 100;
const CSS = [
'@keyframes snowfall-fall { to { transform: translateY(var(--container-height)); } }',
'@keyframes snowfall-sway { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(var(--amp)); } }',
'.snowfall-outer { position: fixed; top: -10px; pointer-events: none; z-index: 999999; animation: snowfall-fall var(--dur) linear infinite var(--delay); }',
'.snowfall-inner { width: var(--size); height: var(--size); background: #fff; border-radius: 50%; opacity: var(--op); animation: snowfall-sway var(--sway-dur) ease-in-out infinite alternate var(--sway-delay); }'
].join(' ');
function r(min, max) { return Math.random() * (max - min) + min; }
function injectStyles() {
const style = document.createElement('style');
style.textContent = CSS;
document.head.appendChild(style);
}
function createFlakes() {
const h = window.innerHeight + 'px';
for (let i = 0; i < COUNT; i++) {
const outer = document.createElement('div');
outer.className = 'snowfall-outer';
outer.style.cssText = [
'left:' + r(0, 100).toFixed(1) + '%;',
'--dur:' + r(4, 10).toFixed(1) + 's;',
'--delay:' + (r(0, 10) * -1).toFixed(1) + 's;',
'--container-height:' + h + ';'
].join(' ');
const inner = document.createElement('div');
inner.className = 'snowfall-inner';
inner.style.cssText = [
'--size:' + r(2, 8).toFixed(1) + 'px;',
'--op:' + r(0.5, 1).toFixed(2) + ';',
'--amp:' + r(-20, 20).toFixed(0) + 'px;',
'--sway-dur:' + r(1.5, 3.5).toFixed(1) + 's;',
'--sway-delay:' + (r(0, 3) * -1).toFixed(1) + 's;'
].join(' ');
outer.appendChild(inner);
document.body.appendChild(outer);
}
}
function init() {
injectStyles();
createFlakes();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})(); Now just append the script to your page.
<script src="path/to/snowfall.js"></script> How the Snowfall JavaScript Works
The whole script is sealed in a protective bubble the moment it runs, so none of its code leaks out and interferes with anything else on the page.
Rather than requiring a separate CSS file, the script writes its own style rules directly into the page — like a contractor who shows up with their own tools instead of asking you to supply them.
Each snowflake is actually two boxes nested inside each other. One falls straight down while the other sways side to side independently inside it. Because the two movements happen on separate elements, they naturally combine into that diagonal drifting motion — the same reason real snowflakes don’t just drop in a straight line.
For each of the 100 flakes, the script rolls the dice on size, speed, opacity, how far it sways, and how fast it sways. No two flakes end up identical, which is what makes the whole effect feel organic rather than like a repeating pattern.
If all 100 flakes started at the top of the screen at the same time, the page would look empty for a few seconds and then suddenly get hit by a blizzard. To avoid that, each flake is given a negative start time. CSS interprets this as if the animation already began several seconds ago, so every flake is already halfway through its fall the moment the page loads, and the snow looks natural right away.
The flakes are also attached to the browser window itself rather than the page. That’s what keeps them visible as you scroll — they’re always in front of everything, like snow falling on the outside of a window you’re looking through from inside.
Finally, the script is polite enough to wait until the page has finished loading before doing anything, so it never stumbles by trying to run before everything is ready.







