AI CSS Animations

One Word at a Time Text

A sentence plays one word at a time in the same spot, like a lyric video cut on the beat: small words whisper, the key word lands big in accent. Every word shares one keyframe, offset by its index.

Also known as: kinetic lyric video text, one word at a time animation, rsvp text animation, word flash text css.

HTML

<div class="txt-one-word-at-a-time" aria-label="Ideas move at the speed of type."><span aria-hidden="true" style="--i: 0; --s: 1; --x: 0em; --y: 0.3em">Ideas</span><span aria-hidden="true" style="--i: 1; --s: 1; --x: -0.4em; --y: 0em">move</span><span aria-hidden="true" style="--i: 2; --s: 0.7; --x: 0em; --y: -0.3em" class="txt-one-word-at-a-time-soft">at</span><span aria-hidden="true" style="--i: 3; --s: 0.7; --x: 0em; --y: 0.3em" class="txt-one-word-at-a-time-soft">the</span><span aria-hidden="true" style="--i: 4; --s: 1.45; --x: 0.6em; --y: 0em" class="txt-one-word-at-a-time-hot">speed</span><span aria-hidden="true" style="--i: 5; --s: 0.7; --x: 0em; --y: -0.3em" class="txt-one-word-at-a-time-soft">of</span><span aria-hidden="true" style="--i: 6; --s: 1.15; --x: 0em; --y: 0.4em">type.</span></div>

CSS

.txt-one-word-at-a-time {
  --c: var(--txt-color, #3b82f6);
  font-size: calc(var(--txt-size, 32px) * 1.6);
  font-family: system-ui, sans-serif;
  font-weight: 800;
  line-height: 1.2;
  display: grid;
  place-items: center;
  min-width: 5em;
  height: 2em;
  letter-spacing: -0.03em;}
.txt-one-word-at-a-time span {
  grid-area: 1 / 1;
  font-size: calc(var(--s) * 1em);
  opacity: 0;
  animation: txt-one-word-at-a-time-cut 4s infinite;
  /* eight beats of 0.5s: seven words, then one beat of silence */
  animation-delay: calc(var(--i) * 0.5s - 4s);
}
.txt-one-word-at-a-time-soft { color: color-mix(in srgb, currentColor 55%, transparent); font-weight: 600; }
.txt-one-word-at-a-time-hot {
  color: var(--c);
  font-style: italic;
  font-weight: 900;
}
@keyframes txt-one-word-at-a-time-cut {
  0%    { opacity: 0; translate: var(--x) var(--y); scale: 1.35; filter: blur(0.06em); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  3.5%  { opacity: 1; translate: 0 0; scale: 1; filter: blur(0); animation-timing-function: linear; }
  11%   { opacity: 1; translate: 0 0; scale: 0.97; animation-timing-function: ease-in; }
  12.5%, 100% { opacity: 0; scale: 0.92; filter: blur(0.04em); }
}
@media (prefers-reduced-motion: reduce) {
  .txt-one-word-at-a-time { display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 0 0.25em; height: auto; font-size: calc(var(--txt-size, 32px) * 1.1); }
  .txt-one-word-at-a-time span { animation: none; opacity: 1; font-size: 1em; }
}

@media (prefers-reduced-motion: reduce) {
  .txt-one-word-at-a-time, .txt-one-word-at-a-time *, .txt-one-word-at-a-time::before, .txt-one-word-at-a-time::after, .txt-one-word-at-a-time *::before, .txt-one-word-at-a-time *::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