DEV Community

Cover image for Public Solving: Let it snow
Chris Bongers
Chris Bongers

Posted on • Originally published at

Public Solving: Let it snow

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:

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>
Enter fullscreen mode Exit fullscreen mode

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

const snowContainer = document.querySelector('.snow');
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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

Top comments (4)

lexlohr profile image
Alex Lohr • Edited

This is awesome. Only one small hint: using box-shadow, you can get multiple snow flakes from the same element.

dailydevtips1 profile image
Chris Bongers

Ah yes!
Must really get my head around using box-shadow it's not really my default goto, even for CSS-art.

(Too old-skool I guess)

star_trooper profile image
Atharva Shirdhankar • Edited

The snowflake graffiti effect is awesome 💯

dailydevtips1 profile image
Chris Bongers

Glad you like it! 👏