Four nixie tubes glow orange behind a fine mesh, with the unlit cathodes faint behind, then flicker through digits and land on a new number, tube by tube. One stepped integer per tube.
Also known as: nixie tube css, retro number display, glowing digits animation, number animation css.
<div class="txt-nixie-tube-counter" aria-label="Nixie display reading 1984, then 2026"> <span class="txt-nixie-tube-counter-tube" aria-hidden="true"><span class="txt-nixie-tube-counter-d0"></span></span> <span class="txt-nixie-tube-counter-tube" aria-hidden="true"><span class="txt-nixie-tube-counter-d1"></span></span> <span class="txt-nixie-tube-counter-tube" aria-hidden="true"><span class="txt-nixie-tube-counter-d2"></span></span> <span class="txt-nixie-tube-counter-tube" aria-hidden="true"><span class="txt-nixie-tube-counter-d3"></span></span> </div>
@property --txt-nixie-tube-counter-d {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
.txt-nixie-tube-counter {
--c: var(--txt-color, #3b82f6);
font-size: calc(var(--txt-size, 32px) * 1);
font-family: system-ui, sans-serif;
font-weight: 700;
line-height: 1.2;
display: inline-flex;
gap: 0.18em;
padding: 0.3em 0.35em 0.4em;
border-radius: 0.3em;
background: linear-gradient(#2a1d14, #120c08);
box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.06), 0 0.4em 1em -0.5em rgb(0 0 0 / 0.55);
--glow: color-mix(in srgb, var(--c) 12%, #ff8a2b);
--t: 8s;}
.txt-nixie-tube-counter-tube {
position: relative;
display: grid;
place-items: center;
width: 1.2em;
height: 1.85em;
border-radius: 0.55em 0.55em 0.25em 0.25em;
background:
radial-gradient(60% 40% at 50% 55%, color-mix(in srgb, var(--glow) 18%, transparent), transparent 75%),
linear-gradient(90deg, rgb(255 255 255 / 0.1), transparent 25%, transparent 75%, rgb(255 255 255 / 0.05)),
#0d0907;
box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12), inset 0 0.3em 0.5em -0.3em rgb(255 255 255 / 0.25);
overflow: hidden;
font-family: "Helvetica Neue", Arial, system-ui, sans-serif;
font-weight: 300;
}
/* the unlit cathodes, faint behind the lit one */
.txt-nixie-tube-counter-tube::before {
content: "8";
position: absolute;
font-size: 1.5em;
color: transparent;
-webkit-text-stroke: 1px rgb(255 200 150 / 0.12);
}
/* the anode mesh */
.txt-nixie-tube-counter-tube::after {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle, transparent 40%, rgb(0 0 0 / 0.4) 42%) 0 0 / 0.11em 0.11em;
pointer-events: none;
}
.txt-nixie-tube-counter-tube > span {
position: relative;
font-size: 1.5em;
font-weight: 400;
color: color-mix(in srgb, var(--glow) 35%, #fff4e0);
text-shadow: 0 0 0.04em #fff, 0 0 0.12em var(--glow), 0 0 0.3em var(--glow), 0 0 0.7em color-mix(in srgb, var(--glow) 70%, transparent);
counter-reset: txt-nixie-tube-counter-n var(--txt-nixie-tube-counter-d);
}
.txt-nixie-tube-counter-tube > span::before { content: counter(txt-nixie-tube-counter-n); }
.txt-nixie-tube-counter-d0 { --txt-nixie-tube-counter-d: 1; animation: txt-nixie-tube-counter-d0 var(--t) step-end infinite, txt-nixie-tube-counter-hum 0.16s steps(2) infinite; }
.txt-nixie-tube-counter-d1 { --txt-nixie-tube-counter-d: 9; animation: txt-nixie-tube-counter-d1 var(--t) step-end infinite, txt-nixie-tube-counter-hum 0.16s steps(2) infinite; }
.txt-nixie-tube-counter-d2 { --txt-nixie-tube-counter-d: 8; animation: txt-nixie-tube-counter-d2 var(--t) step-end infinite, txt-nixie-tube-counter-hum 0.16s steps(2) infinite; }
.txt-nixie-tube-counter-d3 { --txt-nixie-tube-counter-d: 4; animation: txt-nixie-tube-counter-d3 var(--t) step-end infinite, txt-nixie-tube-counter-hum 0.16s steps(2) infinite; }
@keyframes txt-nixie-tube-counter-d0 {
0% { --txt-nixie-tube-counter-d: 1; }
40% { --txt-nixie-tube-counter-d: 7; }
40.88% { --txt-nixie-tube-counter-d: 5; }
41.75% { --txt-nixie-tube-counter-d: 6; }
42.63% { --txt-nixie-tube-counter-d: 4; }
43.5% { --txt-nixie-tube-counter-d: 0; }
44.38% { --txt-nixie-tube-counter-d: 2; }
45.25% { --txt-nixie-tube-counter-d: 2; }
82.5% { --txt-nixie-tube-counter-d: 7; }
83.38% { --txt-nixie-tube-counter-d: 5; }
84.25% { --txt-nixie-tube-counter-d: 6; }
85.13% { --txt-nixie-tube-counter-d: 4; }
86% { --txt-nixie-tube-counter-d: 0; }
86.88% { --txt-nixie-tube-counter-d: 2; }
87.75% { --txt-nixie-tube-counter-d: 1; }
100% { --txt-nixie-tube-counter-d: 1; }
}
@keyframes txt-nixie-tube-counter-d1 {
0% { --txt-nixie-tube-counter-d: 9; }
41.5% { --txt-nixie-tube-counter-d: 1; }
42.38% { --txt-nixie-tube-counter-d: 7; }
43.25% { --txt-nixie-tube-counter-d: 5; }
44.13% { --txt-nixie-tube-counter-d: 6; }
45% { --txt-nixie-tube-counter-d: 4; }
45.88% { --txt-nixie-tube-counter-d: 0; }
46.75% { --txt-nixie-tube-counter-d: 0; }
84% { --txt-nixie-tube-counter-d: 1; }
84.88% { --txt-nixie-tube-counter-d: 7; }
85.75% { --txt-nixie-tube-counter-d: 5; }
86.63% { --txt-nixie-tube-counter-d: 6; }
87.5% { --txt-nixie-tube-counter-d: 4; }
88.38% { --txt-nixie-tube-counter-d: 0; }
89.25% { --txt-nixie-tube-counter-d: 9; }
100% { --txt-nixie-tube-counter-d: 9; }
}
@keyframes txt-nixie-tube-counter-d2 {
0% { --txt-nixie-tube-counter-d: 8; }
43% { --txt-nixie-tube-counter-d: 9; }
43.88% { --txt-nixie-tube-counter-d: 1; }
44.75% { --txt-nixie-tube-counter-d: 7; }
45.63% { --txt-nixie-tube-counter-d: 5; }
46.5% { --txt-nixie-tube-counter-d: 6; }
47.38% { --txt-nixie-tube-counter-d: 4; }
48.25% { --txt-nixie-tube-counter-d: 2; }
85.5% { --txt-nixie-tube-counter-d: 9; }
86.38% { --txt-nixie-tube-counter-d: 1; }
87.25% { --txt-nixie-tube-counter-d: 7; }
88.13% { --txt-nixie-tube-counter-d: 5; }
89% { --txt-nixie-tube-counter-d: 6; }
89.88% { --txt-nixie-tube-counter-d: 4; }
90.75% { --txt-nixie-tube-counter-d: 8; }
100% { --txt-nixie-tube-counter-d: 8; }
}
@keyframes txt-nixie-tube-counter-d3 {
0% { --txt-nixie-tube-counter-d: 4; }
44.5% { --txt-nixie-tube-counter-d: 3; }
45.38% { --txt-nixie-tube-counter-d: 9; }
46.25% { --txt-nixie-tube-counter-d: 1; }
47.13% { --txt-nixie-tube-counter-d: 7; }
48% { --txt-nixie-tube-counter-d: 5; }
48.88% { --txt-nixie-tube-counter-d: 6; }
49.75% { --txt-nixie-tube-counter-d: 6; }
87% { --txt-nixie-tube-counter-d: 3; }
87.88% { --txt-nixie-tube-counter-d: 9; }
88.75% { --txt-nixie-tube-counter-d: 1; }
89.63% { --txt-nixie-tube-counter-d: 7; }
90.5% { --txt-nixie-tube-counter-d: 5; }
91.38% { --txt-nixie-tube-counter-d: 6; }
92.25% { --txt-nixie-tube-counter-d: 4; }
100% { --txt-nixie-tube-counter-d: 4; }
}
@keyframes txt-nixie-tube-counter-hum {
50% { opacity: 0.94; }
}
@media (prefers-reduced-motion: reduce) {
.txt-nixie-tube-counter, .txt-nixie-tube-counter *, .txt-nixie-tube-counter *::before, .txt-nixie-tube-counter *::after { animation: none !important; }
}
@media (prefers-reduced-motion: reduce) {
.txt-nixie-tube-counter, .txt-nixie-tube-counter *, .txt-nixie-tube-counter::before, .txt-nixie-tube-counter::after, .txt-nixie-tube-counter *::before, .txt-nixie-tube-counter *::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.