Snow Fall
Unicode snowflakes driven by CSS keyframes fall in a night-sky loop — JS recycles each flake on animationend for a continuous stream without canvas or rAF.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Atmosphere has 57 effects, including 10 free. Explore the category →
3 usage examples



How it works
Each snowflake is a div.snow2-flake holding a Unicode character (❅, ✼, ❆…). The fall is entirely driven by @keyframes snow2Fall: translateY(-20px) rotate(0deg) → translateY(300px) rotate(360deg) as linear infinite. No requestAnimationFrame, no canvas — the browser's CSS engine handles every frame on the compositor thread.
createSnowflake() builds an element with randomised properties: left 0–100 %, font-size 10–24 px, opacity 0.4–1.0, animation-duration 4–8 s, animation-delay 0–2 s. An animationend listener removes the finished flake and immediately creates a new one — the stream is continuous and memory stays flat (one out, one in).
The .snow2-container sits at position: absolute; inset: 0 with a night-sky linear gradient (#1e3a5f → #0f1c2e) and overflow: hidden clipping flakes at the edges. A text-shadow rgba(255,255,255,.5) 0 0 5px on each flake adds a soft glow suited to the dark background.
The HTML pre-seeds two flakes with inline style (pre-computed durations and delays) so the scene is never empty on first render, before the script fills the pool.
Accessibility
- prefers-reduced-motion not handled: the source code contains no check for this media query — the CSS animation runs unconditionally, even on systems set to reduce motion. Patch manually:
@media (prefers-reduced-motion: reduce) { .snow2-flake { animation: none; } }. - The
div.snow2-flakeelements contain Unicode text (❅, ✼…) withoutaria-hidden="true": a screen reader may announce each flake as they are created dynamically. Addingaria-hidden="true"on.snow2-containeris strongly recommended. - The container carries neither
rolenoraria-label— its purely decorative purpose is invisible to assistive technology. - Flakes carry
pointer-events: none: they do not block clicks or keyboard navigation on elements placed in overlay. - Contrast: the night-sky gradient provides a ratio above 7:1 for white text (#ffffff on #0f1c2e) — the flakes themselves carry no information and are purely decorative.
Browser compatibility
Requires CSS3 animations (@keyframes, animation) and the animationend event — available in all modern browsers since 2014.
If CSS animations are disabled (battery-save mode on some devices), the two HTML-pre-seeded flakes remain visible at fixed positions — the gradient background is shown and no JS errors are thrown.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="snow2-container" id="snowContainer" aria-hidden="true">
<span class="snow-text">Snowflakes</span>
<!-- div.snow2-flake elements are injected dynamically by JS -->
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| snowflakes array (JS) | ['❅','✼','❆','❄'] | Unicode character set used for flakes in createSnowflake() — swap in any winter character or emoji to change the aesthetic. |
| 10 + 14 * Math.random() (JS) | 10–24 px | Flake size range in createSnowflake() — reduce to 8 + 8 * Math.random() for fine snow, raise to 14 + 20 * Math.random() for large flakes. |
| 4 + 4 * Math.random() + "s" (JS) | 4–8 s | Animation duration in createSnowflake() — increase for a slow romantic fall (7 + 5 * Math.random()), decrease for a blizzard (2 + 2 * Math.random()). |
| .4 + .6 * Math.random() (JS) | 0.4–1.0 | Opacity range in createSnowflake() — cap at .3 + .3 * Math.random() for subtle semi-transparent snow on a background image. |
| translateY(300px) — @keyframes snow2Fall (CSS) | 300 px | Fall distance in the CSS animation — match it to your container's actual height so flakes exit fully at the bottom before being recycled. |
| background — .snow2-container (CSS) | linear-gradient(#1e3a5f, #0f1c2e) | Sky gradient — set to transparent or a landscape background-image to layer the effect over an existing hero. |
| color — .snow2-flake (CSS) | #fff | Flake colour — try #b3d9f7 (glacier blue) or #e8f4ff (off-white) for a more natural look on a light background. |
FAQ
.snow2-container.translateY(300px) in @keyframes snow2Fall to match your container's height. If the container is 500 px tall, use translateY(520px) so flakes exit fully at the bottom before being recycled.@media (prefers-reduced-motion: reduce) { .snow2-flake { animation-play-state: paused; } } and guard createSnowflake() with if (matchMedia('(prefers-reduced-motion: reduce)').matches) return; at the top of the function to cut dynamic creation.