30 CSS Text Hover Effects07 / 30
Neon Glow / Flicker Text Effect
A bar sign that ignites on hover: five stacked text-shadows build the tube glow (white-hot core, tight halo, wide bloom), a steps(1) keyframe sputters through the power-on like real gas catching, and one letter — the W, obviously — stays faulty, buzzing on its own clock even after ignition. Off-state isn't invisible: the tubes read as dim glass, the honest resting state of a real sign. Everything is color + text-shadow, so the markup is one anchor and the words stay words.
Published
The code
<section class="cth-07" aria-label="Neon flicker text demo">
<div class="cth-07__stage">
<div class="cth-07__scene">
<a class="cth-07__sign" href="#cth07-top" id="cth07-top" aria-label="Night Owl — cocktails till 3 a.m.">
<span class="cth-07__word" aria-hidden="true">NIGHT</span>
<span class="cth-07__word cth-07__word--pink" aria-hidden="true">O<i class="cth-07__faulty">W</i>L</span>
<span class="cth-07__pill" aria-hidden="true">cocktails · til 3 a.m.</span>
</a>
<p class="cth-07__hint">Hover the sign and hold — ignition is a <code>steps(1)</code> sputter, the glow is five stacked <code>text-shadow</code> layers, and the W was always going to be the problem.</p>
</div>
</div>
</section><section class="cth-07" aria-label="Neon flicker text demo">
<div class="cth-07__stage">
<div class="cth-07__scene">
<a class="cth-07__sign" href="#cth07-top" id="cth07-top" aria-label="Night Owl — cocktails till 3 a.m.">
<span class="cth-07__word" aria-hidden="true">NIGHT</span>
<span class="cth-07__word cth-07__word--pink" aria-hidden="true">O<i class="cth-07__faulty">W</i>L</span>
<span class="cth-07__pill" aria-hidden="true">cocktails · til 3 a.m.</span>
</a>
<p class="cth-07__hint">Hover the sign and hold — ignition is a <code>steps(1)</code> sputter, the glow is five stacked <code>text-shadow</code> layers, and the W was always going to be the problem.</p>
</div>
</div>
</section>.cth-07,
.cth-07 *,
.cth-07 *::before,
.cth-07 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cth-07 {
--wall: oklch(0.16 0.012 310);
--tube: oklch(0.83 0.14 195);
--tube2: oklch(0.73 0.21 350);
--off: oklch(0.42 0.03 220);
--off2: oklch(0.42 0.06 350);
--mut: oklch(0.6 0.02 300);
font-family: ui-rounded,'SF Pro Rounded','Segoe UI',system-ui,sans-serif;
color: oklch(0.93 0.01 300);
}
.cth-07__stage {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
background: radial-gradient(80% 60% at 50% 38%,oklch(0.2 0.02 310),var(--wall) 72%);
padding: clamp(20px,4vw,56px);
container: cth07/inline-size;
}
.cth-07__scene {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(22px,4cqi,34px);
text-align: center;
}
.cth-07__sign {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(8px,1.6cqi,14px);
text-decoration: none;
padding: clamp(20px,4cqi,36px) clamp(26px,5cqi,52px);
border-radius: 22px;
}
.cth-07__sign:focus-visible {
outline: 2px solid var(--tube);
outline-offset: 6px;
}
.cth-07__word {
display: block;
font-size: clamp(52px,12cqi,120px);
font-weight: 800;
letter-spacing: .06em;
line-height: .95;
color: var(--off);
text-shadow: 0 0 .1em color-mix(in oklch,var(--tube) 18%,transparent);
transition: color .45s ease,text-shadow .45s ease;
}
.cth-07__word--pink {
color: var(--off2);
text-shadow: 0 0 .1em color-mix(in oklch,var(--tube2) 18%,transparent);
}
.cth-07__sign:hover .cth-07__word,
.cth-07__sign:focus-visible .cth-07__word {
color: oklch(0.97 0.03 195);
text-shadow: 0 0 .03em oklch(1 0 0/.9),0 0 .12em var(--tube),0 0 .35em var(--tube),0 0 .85em color-mix(in oklch,var(--tube) 65%,transparent),0 0 1.6em color-mix(in oklch,var(--tube) 40%,transparent);
animation: cth07-ignite .95s steps(1,end);
}
.cth-07__sign:hover .cth-07__word--pink,
.cth-07__sign:focus-visible .cth-07__word--pink {
color: oklch(0.94 0.06 350);
text-shadow: 0 0 .03em oklch(1 0 0/.9),0 0 .12em var(--tube2),0 0 .35em var(--tube2),0 0 .85em color-mix(in oklch,var(--tube2) 65%,transparent),0 0 1.6em color-mix(in oklch,var(--tube2) 40%,transparent);
animation: cth07-ignite 1.15s steps(1,end);
}
@keyframes cth07-ignite {
0%,
9%,
24%,
56% {
color: inherit;
text-shadow: none;
opacity: .4;
}
5%,
12%,
28%,
54%,
60%,
100% {
opacity: 1;
}
}
.cth-07__faulty {
font-style: normal;
animation: cth07-buzz-off 5s steps(1,end) infinite;
}
.cth-07__sign:hover .cth-07__faulty,
.cth-07__sign:focus-visible .cth-07__faulty {
animation: cth07-buzz-on 3.2s steps(1,end) infinite;
}
@keyframes cth07-buzz-off {
0%,
100% {
opacity: 1;
}
7%,
9.5%,
42% {
opacity: .55;
}
8%,
43.5%,
71% {
opacity: 1;
}
70% {
opacity: .7;
}
}
@keyframes cth07-buzz-on {
0%,
100% {
opacity: 1;
}
11%,
13%,
57%,
58.6% {
opacity: .5;
}
12%,
14%,
58%,
60% {
opacity: 1;
}
}
.cth-07__pill {
margin-top: 6px;
font-size: clamp(13px,2cqi,17px);
font-weight: 700;
letter-spacing: .22em;
text-transform: lowercase;
color: var(--off2);
border: 2px solid color-mix(in oklch,var(--off2) 60%,transparent);
border-radius: 99px;
padding: 10px 22px;
transition: color .5s ease,border-color .5s ease,box-shadow .5s ease,text-shadow .5s ease;
}
.cth-07__sign:hover .cth-07__pill,
.cth-07__sign:focus-visible .cth-07__pill {
color: oklch(0.94 0.06 350);
border-color: var(--tube2);
text-shadow: 0 0 .3em var(--tube2);
box-shadow: 0 0 .6em color-mix(in oklch,var(--tube2) 55%,transparent),inset 0 0 .5em color-mix(in oklch,var(--tube2) 35%,transparent);
transition-delay: .18s;
}
.cth-07__hint {
font-size: 12.5px;
line-height: 1.7;
color: var(--mut);
max-width: 52ch;
}
.cth-07__hint code {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: .92em;
background: oklch(0.24 0.015 310);
padding: 1px 6px;
border-radius: 4px;
color: var(--tube);
}
@media (prefers-reduced-motion: reduce) {
.cth-07 * {
animation: none !important;
transition-duration: .25s !important;
}
}.cth-07,
.cth-07 *,
.cth-07 *::before,
.cth-07 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cth-07 {
--wall: oklch(0.16 0.012 310);
--tube: oklch(0.83 0.14 195);
--tube2: oklch(0.73 0.21 350);
--off: oklch(0.42 0.03 220);
--off2: oklch(0.42 0.06 350);
--mut: oklch(0.6 0.02 300);
font-family: ui-rounded,'SF Pro Rounded','Segoe UI',system-ui,sans-serif;
color: oklch(0.93 0.01 300);
}
.cth-07__stage {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
background: radial-gradient(80% 60% at 50% 38%,oklch(0.2 0.02 310),var(--wall) 72%);
padding: clamp(20px,4vw,56px);
container: cth07/inline-size;
}
.cth-07__scene {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(22px,4cqi,34px);
text-align: center;
}
.cth-07__sign {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(8px,1.6cqi,14px);
text-decoration: none;
padding: clamp(20px,4cqi,36px) clamp(26px,5cqi,52px);
border-radius: 22px;
}
.cth-07__sign:focus-visible {
outline: 2px solid var(--tube);
outline-offset: 6px;
}
.cth-07__word {
display: block;
font-size: clamp(52px,12cqi,120px);
font-weight: 800;
letter-spacing: .06em;
line-height: .95;
color: var(--off);
text-shadow: 0 0 .1em color-mix(in oklch,var(--tube) 18%,transparent);
transition: color .45s ease,text-shadow .45s ease;
}
.cth-07__word--pink {
color: var(--off2);
text-shadow: 0 0 .1em color-mix(in oklch,var(--tube2) 18%,transparent);
}
.cth-07__sign:hover .cth-07__word,
.cth-07__sign:focus-visible .cth-07__word {
color: oklch(0.97 0.03 195);
text-shadow: 0 0 .03em oklch(1 0 0/.9),0 0 .12em var(--tube),0 0 .35em var(--tube),0 0 .85em color-mix(in oklch,var(--tube) 65%,transparent),0 0 1.6em color-mix(in oklch,var(--tube) 40%,transparent);
animation: cth07-ignite .95s steps(1,end);
}
.cth-07__sign:hover .cth-07__word--pink,
.cth-07__sign:focus-visible .cth-07__word--pink {
color: oklch(0.94 0.06 350);
text-shadow: 0 0 .03em oklch(1 0 0/.9),0 0 .12em var(--tube2),0 0 .35em var(--tube2),0 0 .85em color-mix(in oklch,var(--tube2) 65%,transparent),0 0 1.6em color-mix(in oklch,var(--tube2) 40%,transparent);
animation: cth07-ignite 1.15s steps(1,end);
}
@keyframes cth07-ignite {
0%,
9%,
24%,
56% {
color: inherit;
text-shadow: none;
opacity: .4;
}
5%,
12%,
28%,
54%,
60%,
100% {
opacity: 1;
}
}
.cth-07__faulty {
font-style: normal;
animation: cth07-buzz-off 5s steps(1,end) infinite;
}
.cth-07__sign:hover .cth-07__faulty,
.cth-07__sign:focus-visible .cth-07__faulty {
animation: cth07-buzz-on 3.2s steps(1,end) infinite;
}
@keyframes cth07-buzz-off {
0%,
100% {
opacity: 1;
}
7%,
9.5%,
42% {
opacity: .55;
}
8%,
43.5%,
71% {
opacity: 1;
}
70% {
opacity: .7;
}
}
@keyframes cth07-buzz-on {
0%,
100% {
opacity: 1;
}
11%,
13%,
57%,
58.6% {
opacity: .5;
}
12%,
14%,
58%,
60% {
opacity: 1;
}
}
.cth-07__pill {
margin-top: 6px;
font-size: clamp(13px,2cqi,17px);
font-weight: 700;
letter-spacing: .22em;
text-transform: lowercase;
color: var(--off2);
border: 2px solid color-mix(in oklch,var(--off2) 60%,transparent);
border-radius: 99px;
padding: 10px 22px;
transition: color .5s ease,border-color .5s ease,box-shadow .5s ease,text-shadow .5s ease;
}
.cth-07__sign:hover .cth-07__pill,
.cth-07__sign:focus-visible .cth-07__pill {
color: oklch(0.94 0.06 350);
border-color: var(--tube2);
text-shadow: 0 0 .3em var(--tube2);
box-shadow: 0 0 .6em color-mix(in oklch,var(--tube2) 55%,transparent),inset 0 0 .5em color-mix(in oklch,var(--tube2) 35%,transparent);
transition-delay: .18s;
}
.cth-07__hint {
font-size: 12.5px;
line-height: 1.7;
color: var(--mut);
max-width: 52ch;
}
.cth-07__hint code {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: .92em;
background: oklch(0.24 0.015 310);
padding: 1px 6px;
border-radius: 4px;
color: var(--tube);
}
@media (prefers-reduced-motion: reduce) {
.cth-07 * {
animation: none !important;
transition-duration: .25s !important;
}
}Here's a working CSS Text Hover Effect from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Neon Glow / Flicker Text Effect
Source: https://codefronts.com/motion/css-text-hover-effects/neon-glow-flicker-text-effect/
A bar sign that ignites on hover: five stacked text-shadows build the tube glow (white-hot core, tight halo, wide bloom), a steps(1) keyframe sputters through the power-on like real gas catching, and one letter — the W, obviously — stays faulty, buzzing on its own clock even after ignition. Off-state isn't invisible: the tubes read as dim glass, the honest resting state of a real sign. Everything is color + text-shadow, so the markup is one anchor and the words stay words.
## HTML
```html
<section class="cth-07" aria-label="Neon flicker text demo">
<div class="cth-07__stage">
<div class="cth-07__scene">
<a class="cth-07__sign" href="#cth07-top" id="cth07-top" aria-label="Night Owl — cocktails till 3 a.m.">
<span class="cth-07__word" aria-hidden="true">NIGHT</span>
<span class="cth-07__word cth-07__word--pink" aria-hidden="true">O<i class="cth-07__faulty">W</i>L</span>
<span class="cth-07__pill" aria-hidden="true">cocktails · til 3 a.m.</span>
</a>
<p class="cth-07__hint">Hover the sign and hold — ignition is a <code>steps(1)</code> sputter, the glow is five stacked <code>text-shadow</code> layers, and the W was always going to be the problem.</p>
</div>
</div>
</section>
```
## CSS
```css
.cth-07,
.cth-07 *,
.cth-07 *::before,
.cth-07 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cth-07 {
--wall: oklch(0.16 0.012 310);
--tube: oklch(0.83 0.14 195);
--tube2: oklch(0.73 0.21 350);
--off: oklch(0.42 0.03 220);
--off2: oklch(0.42 0.06 350);
--mut: oklch(0.6 0.02 300);
font-family: ui-rounded,'SF Pro Rounded','Segoe UI',system-ui,sans-serif;
color: oklch(0.93 0.01 300);
}
.cth-07__stage {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
background: radial-gradient(80% 60% at 50% 38%,oklch(0.2 0.02 310),var(--wall) 72%);
padding: clamp(20px,4vw,56px);
container: cth07/inline-size;
}
.cth-07__scene {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(22px,4cqi,34px);
text-align: center;
}
.cth-07__sign {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(8px,1.6cqi,14px);
text-decoration: none;
padding: clamp(20px,4cqi,36px) clamp(26px,5cqi,52px);
border-radius: 22px;
}
.cth-07__sign:focus-visible {
outline: 2px solid var(--tube);
outline-offset: 6px;
}
.cth-07__word {
display: block;
font-size: clamp(52px,12cqi,120px);
font-weight: 800;
letter-spacing: .06em;
line-height: .95;
color: var(--off);
text-shadow: 0 0 .1em color-mix(in oklch,var(--tube) 18%,transparent);
transition: color .45s ease,text-shadow .45s ease;
}
.cth-07__word--pink {
color: var(--off2);
text-shadow: 0 0 .1em color-mix(in oklch,var(--tube2) 18%,transparent);
}
.cth-07__sign:hover .cth-07__word,
.cth-07__sign:focus-visible .cth-07__word {
color: oklch(0.97 0.03 195);
text-shadow: 0 0 .03em oklch(1 0 0/.9),0 0 .12em var(--tube),0 0 .35em var(--tube),0 0 .85em color-mix(in oklch,var(--tube) 65%,transparent),0 0 1.6em color-mix(in oklch,var(--tube) 40%,transparent);
animation: cth07-ignite .95s steps(1,end);
}
.cth-07__sign:hover .cth-07__word--pink,
.cth-07__sign:focus-visible .cth-07__word--pink {
color: oklch(0.94 0.06 350);
text-shadow: 0 0 .03em oklch(1 0 0/.9),0 0 .12em var(--tube2),0 0 .35em var(--tube2),0 0 .85em color-mix(in oklch,var(--tube2) 65%,transparent),0 0 1.6em color-mix(in oklch,var(--tube2) 40%,transparent);
animation: cth07-ignite 1.15s steps(1,end);
}
@keyframes cth07-ignite {
0%,
9%,
24%,
56% {
color: inherit;
text-shadow: none;
opacity: .4;
}
5%,
12%,
28%,
54%,
60%,
100% {
opacity: 1;
}
}
.cth-07__faulty {
font-style: normal;
animation: cth07-buzz-off 5s steps(1,end) infinite;
}
.cth-07__sign:hover .cth-07__faulty,
.cth-07__sign:focus-visible .cth-07__faulty {
animation: cth07-buzz-on 3.2s steps(1,end) infinite;
}
@keyframes cth07-buzz-off {
0%,
100% {
opacity: 1;
}
7%,
9.5%,
42% {
opacity: .55;
}
8%,
43.5%,
71% {
opacity: 1;
}
70% {
opacity: .7;
}
}
@keyframes cth07-buzz-on {
0%,
100% {
opacity: 1;
}
11%,
13%,
57%,
58.6% {
opacity: .5;
}
12%,
14%,
58%,
60% {
opacity: 1;
}
}
.cth-07__pill {
margin-top: 6px;
font-size: clamp(13px,2cqi,17px);
font-weight: 700;
letter-spacing: .22em;
text-transform: lowercase;
color: var(--off2);
border: 2px solid color-mix(in oklch,var(--off2) 60%,transparent);
border-radius: 99px;
padding: 10px 22px;
transition: color .5s ease,border-color .5s ease,box-shadow .5s ease,text-shadow .5s ease;
}
.cth-07__sign:hover .cth-07__pill,
.cth-07__sign:focus-visible .cth-07__pill {
color: oklch(0.94 0.06 350);
border-color: var(--tube2);
text-shadow: 0 0 .3em var(--tube2);
box-shadow: 0 0 .6em color-mix(in oklch,var(--tube2) 55%,transparent),inset 0 0 .5em color-mix(in oklch,var(--tube2) 35%,transparent);
transition-delay: .18s;
}
.cth-07__hint {
font-size: 12.5px;
line-height: 1.7;
color: var(--mut);
max-width: 52ch;
}
.cth-07__hint code {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: .92em;
background: oklch(0.24 0.015 310);
padding: 1px 6px;
border-radius: 4px;
color: var(--tube);
}
@media (prefers-reduced-motion: reduce) {
.cth-07 * {
animation: none !important;
transition-duration: .25s !important;
}
}
```Here's a working CSS Text Hover Effect from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Neon Glow / Flicker Text Effect
Source: https://codefronts.com/motion/css-text-hover-effects/neon-glow-flicker-text-effect/
A bar sign that ignites on hover: five stacked text-shadows build the tube glow (white-hot core, tight halo, wide bloom), a steps(1) keyframe sputters through the power-on like real gas catching, and one letter — the W, obviously — stays faulty, buzzing on its own clock even after ignition. Off-state isn't invisible: the tubes read as dim glass, the honest resting state of a real sign. Everything is color + text-shadow, so the markup is one anchor and the words stay words.
## HTML
```html
<section class="cth-07" aria-label="Neon flicker text demo">
<div class="cth-07__stage">
<div class="cth-07__scene">
<a class="cth-07__sign" href="#cth07-top" id="cth07-top" aria-label="Night Owl — cocktails till 3 a.m.">
<span class="cth-07__word" aria-hidden="true">NIGHT</span>
<span class="cth-07__word cth-07__word--pink" aria-hidden="true">O<i class="cth-07__faulty">W</i>L</span>
<span class="cth-07__pill" aria-hidden="true">cocktails · til 3 a.m.</span>
</a>
<p class="cth-07__hint">Hover the sign and hold — ignition is a <code>steps(1)</code> sputter, the glow is five stacked <code>text-shadow</code> layers, and the W was always going to be the problem.</p>
</div>
</div>
</section>
```
## CSS
```css
.cth-07,
.cth-07 *,
.cth-07 *::before,
.cth-07 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cth-07 {
--wall: oklch(0.16 0.012 310);
--tube: oklch(0.83 0.14 195);
--tube2: oklch(0.73 0.21 350);
--off: oklch(0.42 0.03 220);
--off2: oklch(0.42 0.06 350);
--mut: oklch(0.6 0.02 300);
font-family: ui-rounded,'SF Pro Rounded','Segoe UI',system-ui,sans-serif;
color: oklch(0.93 0.01 300);
}
.cth-07__stage {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
background: radial-gradient(80% 60% at 50% 38%,oklch(0.2 0.02 310),var(--wall) 72%);
padding: clamp(20px,4vw,56px);
container: cth07/inline-size;
}
.cth-07__scene {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(22px,4cqi,34px);
text-align: center;
}
.cth-07__sign {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(8px,1.6cqi,14px);
text-decoration: none;
padding: clamp(20px,4cqi,36px) clamp(26px,5cqi,52px);
border-radius: 22px;
}
.cth-07__sign:focus-visible {
outline: 2px solid var(--tube);
outline-offset: 6px;
}
.cth-07__word {
display: block;
font-size: clamp(52px,12cqi,120px);
font-weight: 800;
letter-spacing: .06em;
line-height: .95;
color: var(--off);
text-shadow: 0 0 .1em color-mix(in oklch,var(--tube) 18%,transparent);
transition: color .45s ease,text-shadow .45s ease;
}
.cth-07__word--pink {
color: var(--off2);
text-shadow: 0 0 .1em color-mix(in oklch,var(--tube2) 18%,transparent);
}
.cth-07__sign:hover .cth-07__word,
.cth-07__sign:focus-visible .cth-07__word {
color: oklch(0.97 0.03 195);
text-shadow: 0 0 .03em oklch(1 0 0/.9),0 0 .12em var(--tube),0 0 .35em var(--tube),0 0 .85em color-mix(in oklch,var(--tube) 65%,transparent),0 0 1.6em color-mix(in oklch,var(--tube) 40%,transparent);
animation: cth07-ignite .95s steps(1,end);
}
.cth-07__sign:hover .cth-07__word--pink,
.cth-07__sign:focus-visible .cth-07__word--pink {
color: oklch(0.94 0.06 350);
text-shadow: 0 0 .03em oklch(1 0 0/.9),0 0 .12em var(--tube2),0 0 .35em var(--tube2),0 0 .85em color-mix(in oklch,var(--tube2) 65%,transparent),0 0 1.6em color-mix(in oklch,var(--tube2) 40%,transparent);
animation: cth07-ignite 1.15s steps(1,end);
}
@keyframes cth07-ignite {
0%,
9%,
24%,
56% {
color: inherit;
text-shadow: none;
opacity: .4;
}
5%,
12%,
28%,
54%,
60%,
100% {
opacity: 1;
}
}
.cth-07__faulty {
font-style: normal;
animation: cth07-buzz-off 5s steps(1,end) infinite;
}
.cth-07__sign:hover .cth-07__faulty,
.cth-07__sign:focus-visible .cth-07__faulty {
animation: cth07-buzz-on 3.2s steps(1,end) infinite;
}
@keyframes cth07-buzz-off {
0%,
100% {
opacity: 1;
}
7%,
9.5%,
42% {
opacity: .55;
}
8%,
43.5%,
71% {
opacity: 1;
}
70% {
opacity: .7;
}
}
@keyframes cth07-buzz-on {
0%,
100% {
opacity: 1;
}
11%,
13%,
57%,
58.6% {
opacity: .5;
}
12%,
14%,
58%,
60% {
opacity: 1;
}
}
.cth-07__pill {
margin-top: 6px;
font-size: clamp(13px,2cqi,17px);
font-weight: 700;
letter-spacing: .22em;
text-transform: lowercase;
color: var(--off2);
border: 2px solid color-mix(in oklch,var(--off2) 60%,transparent);
border-radius: 99px;
padding: 10px 22px;
transition: color .5s ease,border-color .5s ease,box-shadow .5s ease,text-shadow .5s ease;
}
.cth-07__sign:hover .cth-07__pill,
.cth-07__sign:focus-visible .cth-07__pill {
color: oklch(0.94 0.06 350);
border-color: var(--tube2);
text-shadow: 0 0 .3em var(--tube2);
box-shadow: 0 0 .6em color-mix(in oklch,var(--tube2) 55%,transparent),inset 0 0 .5em color-mix(in oklch,var(--tube2) 35%,transparent);
transition-delay: .18s;
}
.cth-07__hint {
font-size: 12.5px;
line-height: 1.7;
color: var(--mut);
max-width: 52ch;
}
.cth-07__hint code {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: .92em;
background: oklch(0.24 0.015 310);
padding: 1px 6px;
border-radius: 4px;
color: var(--tube);
}
@media (prefers-reduced-motion: reduce) {
.cth-07 * {
animation: none !important;
transition-duration: .25s !important;
}
}
```How this works
Neon is a lighting model you can fake with shadow stacking — each layer is one component of how a tube actually looks:
.sign:hover .word{
color:oklch(0.97 0.03 195); /* white-hot core */
text-shadow:
0 0 .03em oklch(1 0 0 / .9), /* filament */
0 0 .12em var(--tube), /* glass glow */
0 0 .35em var(--tube), /* near halo */
0 0 .85em color-mix(in oklch,var(--tube) 65%,transparent),
0 0 1.6em color-mix(in oklch,var(--tube) 40%,transparent); }All radii are in em, so the bloom scales with the headline instead of needing retuning per breakpoint. The ignition is a steps(1,end) animation that toggles between the off and on states at irregular timestamps (0, 9, 12, 24, 28, 54, 57%…) — steps() means no crossfade between sputters, which is exactly how discharge tubes behave; the keyframe ends at 100% lit with forwards, and mouse-out falls back to the plain color/text-shadow transition for a smooth power-down.
The character in the design is the broken letter: one span runs a slow, permanent steps(1) buzz that dips its opacity at odd moments — at rest AND after ignition (where it sputters between 55% and full). One faulty tube makes the whole sign believable; it's also the piece to delete first if the client finds it too honest. The words are wrapped span-per-word with aria-hidden, and the anchor carries an aria-label — screen readers get 'Night Owl, cocktails till 3am', not letter soup.
Make it yours
- Tube color is one token: --tube in oklch — 195 (cyan) and 350 (pink) are the classic pairing here; 145 phosphor green reads arcade, 55 amber reads whiskey bar.
- Ignition tempo: stretch the animation to 2.5s and add two more dark frames for a tired sign; cut to .5s with one sputter for a healthy one.
- Retire the faulty letter by deleting its animation — or move the class to a different span; art-directing WHICH letter is broken is half the fun.
- Layer a hum: box-shadow with the same color stack on a rounded border turns any container into the sign's tube frame (the 'til 3 a.m.' pill downstairs does this).
Gotchas — read before shipping
- text-shadow ignores spread (unlike box-shadow) — you widen the glow by stacking MORE layers at bigger radii, not by adding a fourth length value (it's invalid and kills the whole declaration).
- Five shadow layers × long text = real paint cost. Fine for a sign or hero word; don't neon an entire nav.
- Contrast discipline: the OFF state must still pass contrast against the wall (dim ≠ illegible) — this off-state sits near 4.6:1; check yours.
- Flicker is seizure-adjacent territory: keep dips ≥ 60ms apart, never strobe below that, and hard-disable both flicker animations under prefers-reduced-motion (this demo swaps to a plain crossfade).
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 113+ | 111+ |
text-shadow stacking and steps() run in any 2015+ engine; the floor is oklch()/color-mix() (swap hex/rgba to go older). ui-rounded falls back to system-ui outside Apple platforms — by design.