A forked bolt cracks down onto the word, the letters flash white hot in your accent glow, then slowly cool until the next strike. The bolt is an SVG path drawn with stroke-dashoffset.
Also known as: css lightning effect, lightning text animation, thunder strike text, lightning bolt css.
<div class="txt-lightning-strike-text">
<svg class="txt-lightning-strike-text-bolt" viewBox="0 0 40 50" aria-hidden="true">
<path d="M23 0 L20 8 L24 11 L17 21 L22 23 L15 35 L19 37 L13 50" pathLength="1" />
<path class="txt-lightning-strike-text-fork" d="M17 21 L11 25 L13 28 L7 34" pathLength="1" />
</svg>
<span class="txt-lightning-strike-text-word">THUNDER</span>
</div>.txt-lightning-strike-text {
--c: var(--txt-color, #3b82f6);
font-size: calc(var(--txt-size, 32px) * 1.5);
font-family: system-ui, sans-serif;
font-weight: 900;
line-height: 1.2;
position: relative;
display: inline-flex;
flex-direction: column;
align-items: center;
letter-spacing: 0.1em;}
.txt-lightning-strike-text::before {
content: "";
position: absolute;
inset: -0.4em -1em;
z-index: -1;
background: radial-gradient(closest-side, color-mix(in srgb, var(--c) 30%, transparent), transparent);
opacity: 0;
animation: txt-lightning-strike-text-flash 3.6s linear infinite;
}
.txt-lightning-strike-text-bolt {
width: 1.5em;
height: 1.9em;
margin-bottom: -0.25em;
overflow: visible;
}
.txt-lightning-strike-text-bolt path {
fill: none;
stroke: color-mix(in srgb, var(--c) 55%, #fff);
stroke-width: 2.4;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 1;
stroke-dashoffset: 1;
filter: drop-shadow(0 0 0.03em var(--c)) drop-shadow(0 0 0.12em var(--c));
animation: txt-lightning-strike-text-bolt 3.6s linear infinite;
}
.txt-lightning-strike-text-bolt .txt-lightning-strike-text-fork {
stroke-width: 1.5;
}
.txt-lightning-strike-text-word {
color: color-mix(in srgb, var(--c) 55%, transparent);
text-shadow: 0 0 0 transparent, 0 0 0 transparent;
animation: txt-lightning-strike-text-charge 3.6s cubic-bezier(0.2, 0.7, 0.3, 1) infinite;
}
@keyframes txt-lightning-strike-text-bolt {
0% { stroke-dashoffset: 1; opacity: 1; }
3% { stroke-dashoffset: 0; opacity: 1; }
5% { opacity: 0.2; }
7% { opacity: 1; }
14% { stroke-dashoffset: 0; opacity: 0; }
100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes txt-lightning-strike-text-charge {
0%, 2% { color: color-mix(in srgb, var(--c) 55%, transparent); text-shadow: 0 0 0 transparent, 0 0 0 transparent; }
4% { color: #fff; text-shadow: 0 0 0.08em #fff, 0 0 0.5em var(--c); }
6% { color: color-mix(in srgb, var(--c) 40%, #fff); text-shadow: 0 0 0.04em var(--c), 0 0 0.2em var(--c); }
8% { color: #fff; text-shadow: 0 0 0.08em #fff, 0 0 0.55em var(--c); }
40% { color: color-mix(in srgb, var(--c) 70%, #fff); text-shadow: 0 0 0.04em var(--c), 0 0 0.25em color-mix(in srgb, var(--c) 60%, transparent); }
100% { color: color-mix(in srgb, var(--c) 55%, transparent); text-shadow: 0 0 0 transparent, 0 0 0 transparent; }
}
@keyframes txt-lightning-strike-text-flash {
0%, 2%, 16%, 100% { opacity: 0; }
4%, 8% { opacity: 1; }
6% { opacity: 0.3; }
}
@media (prefers-reduced-motion: reduce) {
.txt-lightning-strike-text::before, .txt-lightning-strike-text-bolt path, .txt-lightning-strike-text-word { animation: none; }
.txt-lightning-strike-text-bolt path { stroke-dashoffset: 0; }
.txt-lightning-strike-text-word { color: var(--c); }
}
@media (prefers-reduced-motion: reduce) {
.txt-lightning-strike-text, .txt-lightning-strike-text *, .txt-lightning-strike-text::before, .txt-lightning-strike-text::after, .txt-lightning-strike-text *::before, .txt-lightning-strike-text *::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.