← Back to gallery
CSS

Multiline Typewriter Line-Step Sizing

A multiline typewriter pattern that grows the reveal container by line-height steps so complete rows appear without partial-line clipping or layout shift.

multiline-typewriterline-heightline-stepheight-increasereduced-motion

Multiline typewriter · line-height steps

Multiline Typewriter Line-Step Sizing

A reveal container grows by line-height units so multiline copy appears one complete row at a time instead of exposing partial lines. Three variants: a release note (3 lines), a chat composer (2 lines), and an editorial quote (4 lines).

Three rows · measured height

Release Note

Three rows reveal in line-height steps, keeping each row fully hidden until its step arrives. Better for short editorial blocks than for long paragraphs that can reflow across breakpoints.

  • line-height
  • height steps
  • multiline

Two rows · fast reveal

Chat Composer

A shorter two-line block shows how the same line-step logic works for compact status copy. The caret sits at the block edge and follows the reveal height rather than individual glyphs.

  • status copy
  • two lines
  • caret

Four rows · slower pacing

Editorial Quote

A slower four-line variant highlights why line-height consistency matters when row count grows. The wrapper fixes the stage height so the reveal does not push surrounding UI as new lines appear.

  • four lines
  • fixed stage
  • readable leading

Line-step inspector

Release Note

  • line-height
  • height steps
  • multiline

Three rows reveal in line-height steps, keeping each row fully hidden until its step arrives. Better for short editorial blocks than for long paragraphs that can reflow across breakpoints.

.line-step {
  --line-count: 3;
  --line-height: 1.35em;
  position: relative;
  width: min(100%, 22ch);
  min-height: calc(var(--line-count) * var(--line-height));
  line-height: 1.35;
  color: #e0f2fe;
  text-shadow: 0 0 22px rgba(103, 232, 249, 0.13);
}

.line-step__copy {
  display: block;
  max-height: var(--line-height);
  overflow: hidden;
  /* steps(N, end) so each row reveals as a discrete jump rather than
     showing a partially clipped line for any frame. */
  animation: line-step-reveal 3.60s steps(3, end) infinite;
}

.line-step__copy span {
  display: block;
  min-height: var(--line-height);
}

@keyframes line-step-reveal {
  0%   { max-height: var(--line-height); }
  100% { max-height: calc(var(--line-count) * var(--line-height)); }
}

@media (prefers-reduced-motion: reduce) {
  .line-step__copy {
    animation: none;
    max-height: none;
  }
}