AI CSS Animations

Typewriter Carriage Return Effect

Like a real typewriter, the paper slides left one character per keystroke, then the carriage returns and feeds a new line. The paper's transform uses the same steps() as the typing.

Also known as: realistic typewriter animation, moving paper typewriter, typewriter line break css.

HTML

<div class="txt-typewriter-carriage-return" aria-label="CHAPTER ONE. It was late.">
  <div class="txt-typewriter-carriage-return-paper" aria-hidden="true">
    <span class="txt-typewriter-carriage-return-line">CHAPTER ONE</span>
    <span class="txt-typewriter-carriage-return-line">It was late.</span>
  </div>
</div>

CSS

.txt-typewriter-carriage-return {
  --c: var(--txt-color, #3b82f6);
  font-size: var(--txt-size, 32px);
  font-family: system-ui, sans-serif;
  font-weight: 700;
  line-height: 1.2;
  position: relative;
  width: 24ch;
  height: 3.45em;
  overflow: hidden;
  font-family: "Courier New", Courier, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 700;
  line-height: 1.3;
  text-align: left;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);}
/* the scale under the typing line: a tick every character, a long one every five */
.txt-typewriter-carriage-return::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 2.8em;
  height: 0.3em;
  background:
    repeating-linear-gradient(90deg, color-mix(in srgb, currentColor 45%, transparent) 0 1px, transparent 1px 5ch) top / 100% 100% no-repeat,
    repeating-linear-gradient(90deg, color-mix(in srgb, currentColor 22%, transparent) 0 1px, transparent 1px 1ch) top / 100% 50% no-repeat;
}
/* the typing point, which rings at the end of a line */
.txt-typewriter-carriage-return::after {
  content: "";
  position: absolute;
  left: 18.5ch;
  top: 3.12em;
  width: 0.3em;
  height: 0.3em;
  margin-left: -0.15em;
  background: var(--c);
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
  animation: txt-typewriter-carriage-return-ding 0.4s ease-out 1.4s;
}
/* the paper: its left edge starts at the typing point */
.txt-typewriter-carriage-return-paper {
  position: absolute;
  top: 1.45em;
  left: 18ch;
  animation: txt-typewriter-carriage-return-carriage 3.7s linear forwards;
}
.txt-typewriter-carriage-return-line {
  display: block;
  width: 0;
  overflow: hidden;
  white-space: pre;
  animation: txt-typewriter-carriage-return-a 1.1s steps(11) 0.3s forwards;
}
.txt-typewriter-carriage-return-line + .txt-typewriter-carriage-return-line {
  color: var(--c);
  animation: txt-typewriter-carriage-return-b 1.2s steps(12) 2.5s forwards;
}
@keyframes txt-typewriter-carriage-return-a {
  99.9%, to { width: 11ch; }
}
@keyframes txt-typewriter-carriage-return-b {
  99.9%, to { width: 12ch; }
}
/* type (paper steps left), ding, return and line feed, type again */
@keyframes txt-typewriter-carriage-return-carriage {
  0%, 8.11% { transform: translate(0, 0); animation-timing-function: steps(11); }
  37.84%, 47.3% { transform: translate(-11ch, 0); animation-timing-function: cubic-bezier(0.6, 0, 0.2, 1); }
  60.81%, 67.57% { transform: translate(0, -1.3em); animation-timing-function: steps(12); }
  99.9%, 100% { transform: translate(-12ch, -1.3em); }
}
@keyframes txt-typewriter-carriage-return-ding {
  40% { transform: translateY(-0.12em) scale(1.7); }
}

@media (prefers-reduced-motion: reduce) {
  .txt-typewriter-carriage-return, .txt-typewriter-carriage-return *, .txt-typewriter-carriage-return::before, .txt-typewriter-carriage-return::after, .txt-typewriter-carriage-return *::before, .txt-typewriter-carriage-return *::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