Creating Randomized Snowfall Animations with LESS
LESS Recursive Mixins
Unlike JavaScript, LESS doesn't have a native for loop. However, you can achieve loop-like behavior using guarded mixins with the when directive. This enables reucrsive function calls:
.snow(@n) when (@n > 0) {
fn();
.snow((@n - 1));
}
.snow(60);
Preventing LESS from Compiling JavaScript Expressions
To generate random snowflakes, we need JavaScript expressions within LESS code. However, LESS will attempt to compile these unless we use proper escaping:
- Unrecognized LESS syntax can be escaped by prrefixing with
~inside a string - JavaScript expressions require backticks to execute
This allows us to create randomized displacement, timing, and scale values:
left: ~"`Math.round(Math.random() * @{windowWidth})`px";
animation: ~"snowani_@{n} `(-Math.random() * 4 + 8).toFixed(2)`s linear infinite";
transform: ~"scale(`(Math.random() * 0.7 + 0.5).toFixed(2)`)";
Complete Implementation
The following LESS code generates a stylesheet with uniquely randomized snowflakes. Each snowflake has distinct size, horizontal position, vertical offset, appearance timing, and fall speed. Building multiple times produces different distributions:
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
@containerWidth: 750;
.snow_wrap {
position: relative;
width: ~"@{containerWidth}px";
height: 100%;
overflow: hidden;
background: rgba(14, 99, 69, 1);
margin: 0 auto;
}
.snow {
position: absolute;
width: 20px;
height: 20px;
&:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
background-color: #fff;
opacity: 1;
border-radius: 100%;
filter: blur(5px);
}
}
.snowflake(@index) when (@index > 0) {
.snow_@{index} {
left: ~"`Math.round(Math.random() * @{containerWidth})`px";
animation: ~"snowani_@{index} `(-Math.random() * 4 + 8).toFixed(2)`s linear infinite";
animation-delay: ~"`(-Math.random() * 8 + 0.2).toFixed(2)`s";
&:after {
transform: ~"scale(`(Math.random() * 0.7 + 0.5).toFixed(2)`)";
}
}
@keyframes ~"snowani_@{index}" {
0% {
transform: translateY(0);
}
100% {
transform: ~"translateY(`Math.round(Math.random() * 200 + 1600)`px)";
}
}
.snowflake((@index - 1));
}
.snowflake(60);
HTML Structure
With Emmet enabled, enter this abbreviation and expand with your editor's shortcut (Ctrl+E or similar):
.snow_wrap>.snow.snow_$*60
This generates 60 uniquely named snowflake elements that the generated CSS will animate.