Looking to add a touch of winter to your website? Why not try adding a snowfall animation effect using CSS? This can be a great way to add some seasonal flair to your site, and it's actually quite easy to do. Plus, it's a great way to improve your CSS skills.
![]() |
How to Create a Snowfall Animation Effect using CSS |
Once you have the basic CSS in place, you can then add additional properties to customize the effect. For example, you can change the color of the snowflakes, or set them to fall at different speeds. You can even add a shadow effect to make them look like they're floating in the air.
Ready to give it a try? Check out this tutorial on how to create a snowfall animation effect using CSS.
In this article, we will be discussing how to create a snowfall animation purely from HTML and CSS code, without the need for Javascript or any external libraries. For this animation, we will be having a background image of a winter setting with small snowballs falling down the screen. As they are falling, they will gradually fade away before appearing again at the top of the screen. In the middle of the screen, we will also have some text.
Approach: The Snowfall Animation will be created using CSS, as described below:
- Create a <div> tag as the container of the entire animation. It has two <div> tags in it, one for text and one for the particles.
- A text container will have a heading and a paragraph using the <h1> and <p> tags.
- Position the text container in the center of the screen by using the position property as absolute. Give the text colors and text shadows according to the colors of the background image.
- The particle container has 15 <div> tags, where each playing the role of snowball.
- Create particles by simply making rounded <div> with white background. Set each of them with the position of absolute, to freely place them on the screen. Spread them evenly from left to right on the top of the screen.
- To make them look like they are coming from the top, place them higher than the viewing height by setting the negative values to the top property.
- Make them come down the screen while moving zig-zag horizontally using the alternating positive and negative x values in the translate() method of the transform property in the various percentages of completion in the animation define using the @keyframe keyword.
- As they come down, their opacity decreases. This animation keeps running infinitely and linearly.
- In order to create it more life-like, set the different durations of animations to each particle & which will disappear a little slower.
Example: This example illustrates the Snowfall Animation using CSS.
- main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width,
initial-scale=1.0">
<title>
GeeksforGeeks Pure CSS Snow-ball Animation
</title>
<link rel="stylesheet"
href="test.css">
</head>
<body>
<div class="container">
<div class="text-content">
<h4>Snowfall Animation</h4>
<p>
Welcome to GeeksforGeeks Learning!
</p>
</div>
<div class="snow-ball-container">
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
<div class="snow-ball"></div>
</div>
</div>
</body>
</html>
- style.css
/* General Style */
* {
padding: 0%;
margin: 0%;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
overflow-x: hidden;
}
/* Container Style */
.container {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
background: url(
'https://media.geeksforgeeks.org/wp-content/uploads/20230104075101/GFG_image.jpeg');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.container::before {
content: "";
position: absolute;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.479);
}
/* Style Text Content */
.text-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
color: rgb(255, 255, 255);
text-shadow: 2px 1px 5px rgb(0, 89, 255);
font-family: Verdana, Geneva, Tahoma, sans-serif;
letter-spacing: 2px;
}
.text-content h1 {
font-size: 4rem;
}
.text-content p {
font-size: 1.2rem;
font-style: italic;
font-weight: lighter;
width: 80%;
}
/* Style Snowballs and Snowflakes */
.snow-ball-container .snow-ball {
position: absolute;
height: 10px;
width: 10px;
border-radius: 50%;
background: white;
}
.snow-ball-container .snow-ball:nth-child(even) {
position: absolute;
width: 16px;
height: 16px;
animation: flake-motion 15s linear infinite;
}
/* Position the Snowballs above the screen */
.snow-ball-container .snow-ball:nth-child(1) {
top: -50%;
left: 5%;
width: 20px;
height: 20px;
animation: snowball-animation 12s linear 2s infinite;
}
.snow-ball-container .snow-ball:nth-child(2) {
top: -20%;
left: 10%;
}
.snow-ball-container .snow-ball:nth-child(3) {
top: -50%;
left: 15%;
animation: snowball-animation 12s linear infinite;
}
.snow-ball-container .snow-ball:nth-child(4) {
top: -10%;
left: 20%;
}
.snow-ball-container .snow-ball:nth-child(5) {
top: -20%;
left: 25%;
width: 20px;
height: 20px;
animation: snowball-animation 12s linear 2s infinite;
}
.snow-ball-container .snow-ball:nth-child(6) {
top: -40%;
left: 30%;
}
.snow-ball-container .snow-ball:nth-child(7) {
top: -30%;
left: 35%;
width: 5px;
height: 5px;
animation: snowball-animation 12s linear infinite;
}
.snow-ball-container .snow-ball:nth-child(8) {
top: -20%;
left: 40%;
}
.snow-ball-container .snow-ball:nth-child(9) {
top: -50%;
left: 45%;
width: 5px;
height: 5px;
animation: snowball-animation 12s linear 2s infinite;
}
.snow-ball-container .snow-ball:nth-child(10) {
top: -5%;
left: 50%;
}
.snow-ball-container .snow-ball:nth-child(11) {
top: -20%;
left: 60%;
animation: snowball-animation 12s linear infinite;
}
.snow-ball-container .snow-ball:nth-child(12) {
top: -10%;
left: 70%;
}
.snow-ball-container .snow-ball:nth-child(13) {
top: -50%;
left: 80%;
width: 5px;
height: 5px;
animation: snowball-animation 12s linear 2s infinite;
}
.snow-ball-container .snow-ball:nth-child(14) {
top: -20%;
left: 90%;
}
.snow-ball-container .snow-ball:nth-child(15) {
top: -50%;
left: 95%;
width: 30px;
height: 30px;
animation: snowball-animation 12s linear infinite;
}
/* Define animations of Snowball and Snowflakes */
@keyframes snowball-animation {
0% {
transform: translate(0);
opacity: 1;
}
20% {
transform: translate(4px, 100px);
opacity: 0.8;
}
40% {
transform: translate(-7px, 200px);
opacity: 0.7;
}
60% {
transform: translate(10px, 400px);
opacity: 0.5;
}
80% {
transform: translate(-14px, 700px);
opacity: 0.2;
}
100% {
transform: translate(16px, 900px);
opacity: 0;
}
}
@keyframes flake-motion {
0% {
transform: translate(-2px, 0);
opacity: 1;
}
20% {
transform: translate(-9px, 200px);
opacity: 0.9;
}
40% {
transform: translate(14px, 300px);
opacity: 0.7;
}
60% {
transform: translate(-22px, 400px);
opacity: 0.6;
}
80% {
transform: translate(30px, 600px);
opacity: 0.5;
}
90% {
transform: translate(-40px 800px);
opacity: 0.3;
}
100% {
transform: translate(52px, 1000px);
opacity: 0;
}
}
Output:
See the Pen Untitled by LittleCodr (@LittleCodr-Mayank) on CodePen.