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>
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
and1vw
. - 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