Heavy clouds roll over a dark sky until a forked bolt strikes and the whole scene flashes twice. The bolts are clip-path polygons, the flash is one overlay animating opacity.
Also known as: thunderstorm background css, lightning flash animation css, storm effect css.
<div class="bgx-lightning-storm" aria-hidden="true"><span></span><span></span></div>
.bgx-lightning-storm {
--c: var(--bgx-color, #3b82f6);
font-size: var(--bgx-size, 16px);
position: absolute;
inset: 0;
overflow: hidden;
--bolt: color-mix(in srgb, var(--c) 35%, #fff);
--cloud: color-mix(in srgb, var(--c) 14%, #2b3144);
background:
radial-gradient(40% 5em at 18% 1em, color-mix(in srgb, var(--cloud), #000 25%) 50%, transparent),
radial-gradient(30% 6.5em at 70% 0, color-mix(in srgb, var(--cloud), #000 20%) 50%, transparent),
linear-gradient(to bottom, #0b0d16, #141a2a 55%, color-mix(in srgb, var(--c) 20%, #1a2033));}
.bgx-lightning-storm::before {
content: "";
position: absolute;
top: -1.5em;
left: 0;
right: -16em;
height: 8em;
background-size: 16em 8em;
background-repeat: repeat-x;
background-image:
radial-gradient(3.6em 2.6em at 0 3.4em, var(--cloud) 55%, transparent),
radial-gradient(3.6em 2.6em at 16em 3.4em, var(--cloud) 55%, transparent),
radial-gradient(3.4em 2.9em at 5em 2.8em, var(--cloud) 55%, transparent),
radial-gradient(3.2em 2.3em at 10.5em 3.6em, var(--cloud) 55%, transparent),
linear-gradient(to bottom, var(--cloud) 2.2em, transparent 4.6em);
animation: bgx-lightning-storm-roll 30s linear infinite;
}
.bgx-lightning-storm::after {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(ellipse 90% 90% at 50% 0, color-mix(in srgb, var(--bolt) 70%, transparent), transparent 75%);
opacity: 0;
animation: bgx-lightning-storm-flash 5s linear infinite;
}
.bgx-lightning-storm span {
position: absolute;
top: 2.5em;
left: var(--x);
width: 5em;
height: 72%;
filter: drop-shadow(0 0 0.35em var(--bolt));
opacity: 0;
animation: bgx-lightning-storm-strike 5s linear var(--delay) infinite;
}
.bgx-lightning-storm span::before,
.bgx-lightning-storm span::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(#fff, var(--bolt));
clip-path: polygon(51% 0, 56% 0, 45% 22%, 62% 32%, 42% 57%, 58% 65%, 32% 100%, 30% 100%, 51% 68%, 35% 60%, 55% 35%, 38% 24%);
}
.bgx-lightning-storm span::after {
clip-path: polygon(58% 33%, 60% 33%, 72% 46%, 66% 52%, 84% 72%, 83% 72%, 64% 53%, 70% 47%);
}
.bgx-lightning-storm span:nth-child(1) { --x: 55%; --delay: 0s; }
.bgx-lightning-storm span:nth-child(2) { --x: 14%; --delay: -2.5s; }
@keyframes bgx-lightning-storm-roll {
to { transform: translateX(-16em); }
}
@keyframes bgx-lightning-storm-strike {
0%, 5% { opacity: 0; }
6% { opacity: 1; }
8% { opacity: 0.2; }
10% { opacity: 1; }
15% { opacity: 0; }
100% { opacity: 0; }
}
@keyframes bgx-lightning-storm-flash {
0%, 5%, 55% { opacity: 0; }
6%, 56% { opacity: 0.85; }
8%, 58% { opacity: 0.15; }
10%, 60% { opacity: 0.7; }
16%, 66% { opacity: 0; }
100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.bgx-lightning-storm, .bgx-lightning-storm *, .bgx-lightning-storm::before, .bgx-lightning-storm::after, .bgx-lightning-storm *::before, .bgx-lightning-storm *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--bgx-color on the element or a parent.
Currently previewing #3b82f6.--bgx-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.