A neon sign whose frame is a dim glass tube with two sparks of light racing around it, while the lettering burns steadily inside. The frame is one SVG path with pathLength set to 100.
Also known as: neon border animation css, light running around border, glowing frame text.
<div class="txt-neon-border-trace">
<svg class="txt-neon-border-trace-frame" viewBox="0 0 160 52" aria-hidden="true">
<path pathLength="100" d="M12 2 H148 A10 10 0 0 1 158 12 V40 A10 10 0 0 1 148 50 H12 A10 10 0 0 1 2 40 V12 A10 10 0 0 1 12 2 Z" />
<path class="txt-neon-border-trace-spark" pathLength="100" d="M12 2 H148 A10 10 0 0 1 158 12 V40 A10 10 0 0 1 148 50 H12 A10 10 0 0 1 2 40 V12 A10 10 0 0 1 12 2 Z" />
</svg>
<span class="txt-neon-border-trace-text">OPEN 24/7</span>
</div>.txt-neon-border-trace {
--c: var(--txt-color, #3b82f6);
font-size: var(--txt-size, 32px);
font-family: system-ui, sans-serif;
font-weight: 700;
line-height: 1.2;
position: relative;
display: inline-grid;
place-items: center;
width: 8em;
height: 2.6em;
letter-spacing: 0.1em;}
.txt-neon-border-trace-frame {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
overflow: visible;
}
.txt-neon-border-trace-frame path {
fill: none;
stroke: color-mix(in srgb, var(--c) 35%, transparent);
stroke-width: 1.6;
}
/* 20 + 30 = 50, two sparks per lap; the offset loops by one full lap */
.txt-neon-border-trace-frame .txt-neon-border-trace-spark {
stroke: color-mix(in srgb, var(--c) 60%, #fff);
stroke-width: 2.4;
stroke-linecap: round;
stroke-dasharray: 20 30;
filter: drop-shadow(0 0 0.04em var(--c)) drop-shadow(0 0 0.12em var(--c));
animation: txt-neon-border-trace-run 2.6s linear infinite;
}
.txt-neon-border-trace-text {
position: relative;
padding-left: 0.1em;
color: color-mix(in srgb, var(--c) 30%, #fff);
text-shadow: 0 0 0.01em var(--c), 0 0 0.03em var(--c), 0 0 0.1em var(--c), 0 0 0.3em color-mix(in srgb, var(--c) 70%, transparent), 0 0 0.6em color-mix(in srgb, var(--c) 40%, transparent);
}
@keyframes txt-neon-border-trace-run {
to { stroke-dashoffset: -100; }
}
@media (prefers-reduced-motion: reduce) {
.txt-neon-border-trace, .txt-neon-border-trace *, .txt-neon-border-trace::before, .txt-neon-border-trace::after, .txt-neon-border-trace *::before, .txt-neon-border-trace *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--txt-color on the element or a parent.
Currently previewing #3b82f6.--txt-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 40px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.