AI CSS Animations

Nixie Tube Counter

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.

HTML

<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>

CSS

@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;
  }
}

Customizing this snippet

  • Color: set --txt-color on the element or a parent. Currently previewing #3b82f6.
  • Font size: set --txt-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 40px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar text animations