Two neon tubes wash a dark wall in magenta and cyan, flicker now and then, and ripple in the wet floor below. Each reflection shares its tube's flicker animation, so the pair stays in sync.
Also known as: neon background css animation, neon lights background, cyberpunk glow background.
<div class="bgx-neon-glow" aria-hidden="true"><span></span><span></span><span></span><span></span><span></span></div>
.bgx-neon-glow {
--c: var(--bgx-color, #3b82f6);
font-size: var(--bgx-size, 16px);
position: absolute;
inset: 0;
overflow: hidden;
--n1: oklch(from var(--c) 0.66 0.27 calc(h + 70));
--n2: oklch(from var(--c) 0.84 0.14 calc(h - 60));
background: linear-gradient(#0a0514, #0d0719 64%, #05030a 64%, #0b0714);
isolation: isolate;
}
.bgx-neon-glow span {
position: absolute;
mix-blend-mode: screen;
animation: bgx-neon-glow-flicker var(--t) linear var(--d) infinite;
}
.bgx-neon-glow span:nth-child(-n + 4) {
left: calc(var(--x) - max(11em, 21%));
width: max(22em, 42%);
}
.bgx-neon-glow span:nth-child(1),
.bgx-neon-glow span:nth-child(2) {
top: -20%;
height: 90%;
border-radius: 50%;
background: radial-gradient(closest-side, var(--n), transparent);
}
.bgx-neon-glow span:nth-child(1)::before,
.bgx-neon-glow span:nth-child(2)::before {
content: "";
position: absolute;
left: 50%;
top: 24%;
width: 0.32em;
height: 44%;
translate: -50% 0;
border-radius: 1em;
background: color-mix(in srgb, var(--n) 45%, #fff);
box-shadow: 0 0 0.5em 0.1em var(--n), 0 0 2.2em 0.4em var(--n);
}
.bgx-neon-glow span:nth-child(odd):not(:last-child) { --x: 20%; --n: var(--n1); --t: 7s; --d: -1s; }
.bgx-neon-glow span:nth-child(even) { --x: 80%; --n: var(--n2); --t: 5.3s; --d: -3s; }
.bgx-neon-glow span:nth-child(3),
.bgx-neon-glow span:nth-child(4) {
top: 64%;
bottom: 0;
background:
repeating-linear-gradient(transparent 0 0.3em, rgb(5 3 10 / 0.6) 0.3em 0.42em),
radial-gradient(ellipse 16% 100% at 50% 0%, var(--n), transparent);
opacity: 0.7;
animation:
bgx-neon-glow-flicker var(--t) linear var(--d) infinite,
bgx-neon-glow-ripple 1.4s linear infinite;
}
.bgx-neon-glow span:nth-child(5) {
left: -20%;
right: -20%;
top: 26%;
height: 32%;
border-radius: 50%;
background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--n1) 30%, transparent) 30%, color-mix(in srgb, var(--n2) 26%, transparent) 70%, transparent);
filter: blur(1.4em);
animation: bgx-neon-glow-haze 9s cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}
@keyframes bgx-neon-glow-flicker {
0%, 17%, 21%, 24%, 58%, 61%, 100% { opacity: 1; }
19%, 23% { opacity: 0.35; }
59.5% { opacity: 0.6; }
}
@keyframes bgx-neon-glow-ripple {
to { background-position: 0 0.42em, 0 0; }
}
@keyframes bgx-neon-glow-haze {
from { transform: translateX(-8%) scaleY(0.8); opacity: 0.6; }
to { transform: translateX(8%) scaleY(1.2); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
.bgx-neon-glow, .bgx-neon-glow *, .bgx-neon-glow::before, .bgx-neon-glow::after, .bgx-neon-glow *::before, .bgx-neon-glow *::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.