Subscribe

Public Solving: Let it snow

✍️

How to create animated snow in CSS

29 Dec, 2021 · 4 min read

Today the elves asked us to make some snow animations! This is a pretty exciting task as we have to get out our creative hats.

You can find the complete puzzle here.

So far I've done some confetti in CSS, and an animated snake. Today we can add animated snow to the list.

We are free to make it in any way we want.

My results looks like this:

See the Pen Untitled by Chris Bongers (@rebelchris) on CodePen.

Thinking about a solution

I'm right away thinking in the lines of the CSS confetti I made, where we repeat 50 divs and use CSS to randomize some elements of every snowflake.

The things I want to randomize:

  • Size of the snowflake
  • Position left to right on the screen
  • Animation speed and delay
  • Falling animation

This would be the easiest to use SASS, which isn't mentioned as a no-go, so we'll be implementing that.

For the creation of 50 divs, we could use pug, but I inject them through JavaScript.

Let me guide you through this process step by step.

Making animated snow in JavaScript

First, we need to add our 50 divs into the main container. This main container already exists and looks like this:

<main class="snow"></main>

We can fetch this element in our provided JavaScript file by using the following code.

const snowContainer = document.querySelector('.snow');

Then we'll need to create a loop that runs 50 times and adds a new element into this one.

[...Array(50)].forEach((_, i) => {
  const snowFlake = document.createElement('div');
  snowFlake.classList.add('snowflake');
  snowContainer.append(snowFlake);
});

This forEach hack is a simple way to generate x looped lines. We then use the createElement function to create a new div and add the snowflake class. After which, we add out to our container element.

Enable SCSS in Vite

Now that we have these 50 divs in the viewport, we need to change the default CSS import to work with SASS files.

Luckily for us, Vite already supports this out of the box. We just need to install the preprocessor.

npm install -D sass

Then we can change our file from style.css to style.scss. And modify the import in the main.js to look like this:

import './style.scss';

Right, we can now leverage the massive powers of SCSS.

Styling the snowflake elements

There are some elements to our snowflake that never really change. We can style those in a general fashion.

.snowflake {
  --size: 1vw;
  background: #fff;
  border-radius: 50%;
  position: absolute;
  width: var(--size);
  height: var(--size);
  top: -5vh;
}

This sets a basic viewport-based snowflake. It will start outside of the viewport on the negative top side.

Then we want to create a loop to add our differences to each individual snowflake.

@for $i from 1 through 50 {
  .snowflake:nth-child(#{$i}) {
    --size: #{random(10) * 0.1}vw;
    left: #{random(100)}vw;
    animation: snowfall #{10 + random(10)}s linear infinite;
    animation-delay: -#{random(15)}s;
  }
}

Here we loop 50 times, and for each of the snowflake, we set the following:

  • Random size: between 0.1vw and 1vw.
  • The left position 0-100% of the viewport width
  • The animation time and a custom delay, so they don't all fall at the same time

The animation looks like this:

@keyframes snowfall {
  0% {
    transform: translate3d(0, 0, 0);
  }
  100% {
    transform: translate3d(0, 110vh, 0);
  }
}

At this point, we get the random flakes falling down, but they fall straight down, so maybe we should add a slight offset to mix things up.

To achieve this, we need a horizontal start and endpoint. This should be a random number based on a percentage of the viewport's width. As we don't want the snowflakes to fall across the whole screen.

--horizontal-start: #{random(20) - 10}vw;
--horizontal-end: #{random(20) - 10}vw;

And then, we can modify our animation to start and end on these values.

@keyframes snowfall {
  0% {
    transform: translate3d(var(--horizontal-start), 0, 0);
  }
  100% {
    transform: translate3d(var(--horizontal-end), 110vh, 0);
  }
}

That's it, my version of CSS-based animated snow ❄️.

I would be delighted to see other people's snow animations, as some are wizards with CSS 👀.

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Spread the knowledge with fellow developers on Twitter
Tweet this tip
Powered by Webmentions - Learn more

Read next 📖

Public Solving: Making a CSS art Christmas tree

23 Dec, 2021 · 3 min read

Public Solving: Making a CSS art Christmas tree

Bringing perspective to CSS

7 Aug, 2022 · 2 min read

Bringing perspective to CSS

Join 1900 devs and subscribe to my newsletter