Rain on a window
Rain streaks on a window with wet-glass refraction
Techniques: feTurbulence · feDisplacementMap · animateMotion · staggered-delays
<!--
============================================================
SVGarden — https://www.svgarden.dev
Author : Simon-Pierre Boucher
Contact: contact@spboucher.ai
File : snippets/backgrounds/rain-window.html
Desc : Rain streaks on a window with wet-glass refraction
============================================================
-->
<div class="sg-rain-window" style="--sg-color:#31445A; --sg-size:180px; --sg-duration:1.6s;">
<svg viewBox="0 0 320 180" preserveAspectRatio="xMidYMid slice" aria-hidden="true" focusable="false">
<defs>
<linearGradient id="sg-rain-window-sky" x1="0" y1="0" x2="0" y2="1">
<stop class="sg-rain-window-tint" offset="0" />
<stop offset="1" stop-color="#0f1722" />
</linearGradient>
<filter id="sg-rain-window-warp" x="-10%" y="-10%" width="120%" height="120%">
<feTurbulence type="fractalNoise" baseFrequency="0.012 0.05" numOctaves="2" result="sg-noise">
<animate attributeName="baseFrequency" dur="9s" repeatCount="indefinite"
values="0.012 0.05;0.016 0.06;0.012 0.05" />
</feTurbulence>
<feDisplacementMap in="SourceGraphic" in2="sg-noise" scale="16" />
</filter>
</defs>
<rect x="0" y="0" width="320" height="180" fill="url(#sg-rain-window-sky)" />
<rect class="sg-rain-window-wet" x="-20" y="-20" width="360" height="220" fill="url(#sg-rain-window-sky)" />
<g class="sg-rain-window-streaks">
<line x1="30" y1="-30" x2="27" y2="-6" />
<line x1="74" y1="-42" x2="71" y2="-14" />
<line x1="118" y1="-26" x2="115" y2="-4" />
<line x1="162" y1="-38" x2="159" y2="-10" />
<line x1="206" y1="-30" x2="203" y2="-8" />
<line x1="248" y1="-44" x2="245" y2="-16" />
<line x1="284" y1="-28" x2="281" y2="-6" />
<line x1="308" y1="-40" x2="305" y2="-14" />
</g>
<circle class="sg-rain-window-drop1" cx="96" cy="0" r="2.6">
<animateMotion dur="8s" begin="-2s" repeatCount="indefinite"
path="M0 -10 q 4 30 -3 58 q -5 26 2 52 q 5 26 -2 50 q -4 20 1 44" />
</circle>
<circle class="sg-rain-window-drop2" cx="228" cy="0" r="2.1">
<animateMotion dur="11s" begin="-6s" repeatCount="indefinite"
path="M0 -10 q -4 34 3 62 q 5 28 -3 54 q -4 24 3 48 q 3 18 -2 40" />
</circle>
</svg>
</div>
<style>
.sg-rain-window {
width: 100%;
min-width: 240px;
height: var(--sg-size);
overflow: hidden;
border-radius: 8px;
}
.sg-rain-window svg {
display: block;
width: 100%;
height: 100%;
}
.sg-rain-window-tint {
stop-color: var(--sg-color);
}
.sg-rain-window-wet {
filter: url(#sg-rain-window-warp);
opacity: 0.75;
}
.sg-rain-window-streaks line {
stroke: #dbe6f3;
stroke-width: 1.4;
stroke-linecap: round;
opacity: 0.32;
animation: sg-rain-window-fall var(--sg-duration) linear infinite;
}
.sg-rain-window-streaks line:nth-of-type(2) { animation-duration: calc(var(--sg-duration) * 0.8); animation-delay: calc(var(--sg-duration) * -0.4); }
.sg-rain-window-streaks line:nth-of-type(3) { animation-duration: calc(var(--sg-duration) * 1.25); animation-delay: calc(var(--sg-duration) * -0.9); }
.sg-rain-window-streaks line:nth-of-type(4) { animation-duration: calc(var(--sg-duration) * 0.7); animation-delay: calc(var(--sg-duration) * -0.2); }
.sg-rain-window-streaks line:nth-of-type(5) { animation-duration: calc(var(--sg-duration) * 1.1); animation-delay: calc(var(--sg-duration) * -0.7); }
.sg-rain-window-streaks line:nth-of-type(6) { animation-duration: calc(var(--sg-duration) * 0.85); animation-delay: calc(var(--sg-duration) * -0.55); }
.sg-rain-window-streaks line:nth-of-type(7) { animation-duration: calc(var(--sg-duration) * 1.3); animation-delay: calc(var(--sg-duration) * -0.3); }
.sg-rain-window-streaks line:nth-of-type(8) { animation-duration: calc(var(--sg-duration) * 0.75); animation-delay: calc(var(--sg-duration) * -0.65); }
.sg-rain-window-drop1,
.sg-rain-window-drop2 {
fill: #e7eef8;
opacity: 0.5;
}
@keyframes sg-rain-window-fall {
from { transform: translateY(0); }
to { transform: translateY(230px); }
}
</style>