Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
CSS Rain Effect

CSS Rain Effect

Looks best with a taller window/layout.

Rain drop elements animate down the screen, stem element inside animates to disappear toward the end of the drop's fall, splat element animates after the stem disappears.

JavaScript used to randomly position drop elements across the screen, slightly randomize their animation duration and delay, and also stagger their top position. Randomizing delay makes sure the drops don't fall in one sheet, randomizing duration keeps them from falling in the same constant synchronization. Staggering top position makes it so the splats don't fall in a single line.

Splatters are unfortunately disabled by default as it is rather intensive and significantly lowers framerate on most machines (in Chrome that is--FireFox and Edge are smoother actually). You can hit the splat toggle to turn it on. The effect is achieved by putting a dotted border-top on an ellipse element, and animating it from scale(0) to scale(1). You can get a better look at it by enabling the single and splat toggles.

There's also a back row you can enable, which is positioned upwards and mirrored.

Does not work well with IE11 at all for whatever reason. Rain drops will not even show unless you jiggle the window size a bit, and at that point all the animations are out of sync.

A Pen by Aaron Rickle on CodePen.

License.

<!-- check the Comments for more info -->
<body class="back-row-toggle splat-toggle">
<div class="rain front-row"></div>
<div class="rain back-row"></div>
<div class="toggles">
<div class="splat-toggle toggle active">SPLAT</div>
<div class="back-row-toggle toggle active">BACK<br>ROW</div>
<div class="single-toggle toggle">SINGLE</div>
</div>
</body>
var makeItRain = function() {
//clear out everything
$('.rain').empty();
var increment = 0;
var drops = "";
var backDrops = "";
while (increment < 100) {
//couple random numbers to use for various randomizations
//random number between 98 and 1
var randoHundo = (Math.floor(Math.random() * (98 - 1 + 1) + 1));
//random number between 5 and 2
var randoFiver = (Math.floor(Math.random() * (5 - 2 + 1) + 2));
//increment
increment += randoFiver;
//add in a new raindrop with various randomizations to certain CSS properties
drops += '<div class="drop" style="left: ' + increment + '%; bottom: ' + (randoFiver + randoFiver - 1 + 100) + '%; animation-delay: 0.' + randoHundo + 's; animation-duration: 0.5' + randoHundo + 's;"><div class="stem" style="animation-delay: 0.' + randoHundo + 's; animation-duration: 0.5' + randoHundo + 's;"></div><div class="splat" style="animation-delay: 0.' + randoHundo + 's; animation-duration: 0.5' + randoHundo + 's;"></div></div>';
backDrops += '<div class="drop" style="right: ' + increment + '%; bottom: ' + (randoFiver + randoFiver - 1 + 100) + '%; animation-delay: 0.' + randoHundo + 's; animation-duration: 0.5' + randoHundo + 's;"><div class="stem" style="animation-delay: 0.' + randoHundo + 's; animation-duration: 0.5' + randoHundo + 's;"></div><div class="splat" style="animation-delay: 0.' + randoHundo + 's; animation-duration: 0.5' + randoHundo + 's;"></div></div>';
}
$('.rain.front-row').append(drops);
$('.rain.back-row').append(backDrops);
}
$('.splat-toggle.toggle').on('click', function() {
$('body').toggleClass('splat-toggle');
$('.splat-toggle.toggle').toggleClass('active');
makeItRain();
});
$('.back-row-toggle.toggle').on('click', function() {
$('body').toggleClass('back-row-toggle');
$('.back-row-toggle.toggle').toggleClass('active');
makeItRain();
});
$('.single-toggle.toggle').on('click', function() {
$('body').toggleClass('single-toggle');
$('.single-toggle.toggle').toggleClass('active');
makeItRain();
});
makeItRain();
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
overflow: hidden;
background: linear-gradient(to bottom, #202020, #111119);
}
.rain {
position: absolute;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
}
.rain.back-row {
display: none;
z-index: 1;
bottom: 60px;
opacity: 0.5;
}
body.back-row-toggle .rain.back-row {
display: block;
}
.drop {
position: absolute;
bottom: 100%;
width: 15px;
height: 120px;
pointer-events: none;
animation: drop 0.5s linear infinite;
}
@keyframes drop {
0% {
transform: translateY(0vh);
}
75% {
transform: translateY(90vh);
}
100% {
transform: translateY(90vh);
}
}
.stem {
width: 1px;
height: 60%;
margin-left: 7px;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.25));
animation: stem 0.5s linear infinite;
}
@keyframes stem {
0% {
opacity: 1;
}
65% {
opacity: 1;
}
75% {
opacity: 0;
}
100% {
opacity: 0;
}
}
.splat {
width: 15px;
height: 10px;
border-top: 2px dotted rgba(255, 255, 255, 0.5);
border-radius: 50%;
opacity: 1;
transform: scale(0);
animation: splat 0.5s linear infinite;
display: none;
}
body.splat-toggle .splat {
display: block;
}
@keyframes splat {
0% {
opacity: 1;
transform: scale(0);
}
80% {
opacity: 1;
transform: scale(0);
}
90% {
opacity: 0.5;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(1.5);
}
}
.toggles {
position: absolute;
top: 0;
left: 0;
z-index: 3;
}
.toggle {
position: absolute;
left: 20px;
width: 50px;
height: 50px;
line-height: 51px;
box-sizing: border-box;
text-align: center;
font-family: sans-serif;
font-size: 10px;
font-weight: bold;
background-color: rgba(255, 255, 255, 0.2);
color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
cursor: pointer;
transition: background-color 0.3s;
}
.toggle:hover {
background-color: rgba(255, 255, 255, 0.25);
}
.toggle:active {
background-color: rgba(255, 255, 255, 0.3);
}
.toggle.active {
background-color: rgba(255, 255, 255, 0.4);
}
.splat-toggle {
top: 20px;
}
.back-row-toggle {
top: 90px;
line-height: 12px;
padding-top: 14px;
}
.single-toggle {
top: 160px;
}
body.single-toggle .drop {
display: none;
}
body.single-toggle .drop:nth-child(10) {
display: block;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment