A field of glowing dots stretches into the distance and rolls in slow swells, like a 3D particle wave in a dark hero. Each row of dots lifts on a staggered delay inside a preserve-3d plane.
Also known as: wave css background, 3d dot wave background, dotted wave animation css, particle wave background.
<div class="bgx-dotted-wave" aria-hidden="true"><span class="bgx-dotted-wave-plane"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></div>
.bgx-dotted-wave {
--c: var(--bgx-color, #3b82f6);
font-size: var(--bgx-size, 16px);
position: absolute;
inset: 0;
overflow: hidden;
background: radial-gradient(ellipse 90% 70% at 50% 100%, color-mix(in srgb, var(--c) 28%, #0a0c18), #04050a 75%);
perspective: 18em;
perspective-origin: 50% 0%;}
.bgx-dotted-wave-plane {
position: absolute;
left: -40%;
right: -40%;
bottom: -30%;
height: 26.4em;
display: grid;
grid-auto-rows: 1.2em;
transform: rotateX(72deg) rotateZ(-6deg);
transform-origin: 50% 100%;
transform-style: preserve-3d;
}
.bgx-dotted-wave::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(#04050a 18%, transparent 60%);
}
.bgx-dotted-wave-plane span {
background: radial-gradient(circle, color-mix(in srgb, var(--c) 40%, #fff) 0.13em, transparent 0.17em) 0 50% / 1.2em 1.2em repeat-x;
animation: bgx-dotted-wave-swell 2.4s cubic-bezier(0.45, 0, 0.55, 1) calc(var(--i) * -0.4s) infinite alternate;
}
.bgx-dotted-wave-plane span:nth-child(1) { --i: 0; }
.bgx-dotted-wave-plane span:nth-child(2) { --i: 1; }
.bgx-dotted-wave-plane span:nth-child(3) { --i: 2; }
.bgx-dotted-wave-plane span:nth-child(4) { --i: 3; }
.bgx-dotted-wave-plane span:nth-child(5) { --i: 4; }
.bgx-dotted-wave-plane span:nth-child(6) { --i: 5; }
.bgx-dotted-wave-plane span:nth-child(7) { --i: 6; }
.bgx-dotted-wave-plane span:nth-child(8) { --i: 7; }
.bgx-dotted-wave-plane span:nth-child(9) { --i: 8; }
.bgx-dotted-wave-plane span:nth-child(10) { --i: 9; }
.bgx-dotted-wave-plane span:nth-child(11) { --i: 10; }
.bgx-dotted-wave-plane span:nth-child(12) { --i: 11; }
.bgx-dotted-wave-plane span:nth-child(13) { --i: 12; }
.bgx-dotted-wave-plane span:nth-child(14) { --i: 13; }
.bgx-dotted-wave-plane span:nth-child(15) { --i: 14; }
.bgx-dotted-wave-plane span:nth-child(16) { --i: 15; }
.bgx-dotted-wave-plane span:nth-child(17) { --i: 16; }
.bgx-dotted-wave-plane span:nth-child(18) { --i: 17; }
.bgx-dotted-wave-plane span:nth-child(19) { --i: 18; }
.bgx-dotted-wave-plane span:nth-child(20) { --i: 19; }
.bgx-dotted-wave-plane span:nth-child(21) { --i: 20; }
.bgx-dotted-wave-plane span:nth-child(22) { --i: 21; }
@keyframes bgx-dotted-wave-swell {
from { transform: translateZ(-1em); opacity: 0.3; }
to { transform: translateZ(1em); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
.bgx-dotted-wave, .bgx-dotted-wave::before, .bgx-dotted-wave::after, .bgx-dotted-wave *, .bgx-dotted-wave *::before, .bgx-dotted-wave *::after { animation-play-state: paused; }
}
@media (prefers-reduced-motion: reduce) {
.bgx-dotted-wave, .bgx-dotted-wave *, .bgx-dotted-wave::before, .bgx-dotted-wave::after, .bgx-dotted-wave *::before, .bgx-dotted-wave *::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.