Typing CSS animation

by anoopsuda

HTML

<div class="type-wrap" aria-live="polite">
  <!--
    For each .line:
      1) Put your visible text between the div tags.
      2) Set --chars equal to the visible character count (including spaces/punctuation).
         e.g. "Hi there πŸ‘‹" has 11 characters (count emoji as 1).
      3) Set --delay to the total animation-duration of previous lines (or let CSS compute by hand).
         Example below shows automatic delays calculated manually for demo.
  -->

  <!-- Line 1: 22 characters (count spaces & punctuation). Adjust --chars if you change text. -->
  <div class="line typing" style="--chars:22; --delay:0s;">
    Hi there πŸ‘‹ β€” welcome!
  </div>

  <!-- Line 2: 49 chars. Delay equals duration of line1: 22 * 0.06s = 1.32s -->
  <div class="line typing" style="--chars:49; --delay:1.32s;">
    I'm here to help you create  
  </div>

  <div class="line typing" style="--chars:49; --delay:2.32s;">
    your innovation story submission  
  </div>

  <div class="line typing" style="--chars:49; --delay:3.32s;">
      β€” quick and guided.
  </div>

  <!-- Line 3: 24 chars. Delay equals sum durations of line1 + line2 = 1.32s + 2.94s = 4.26s -->
  <div class="line typing" style="--chars:24; --delay:4.26s;">
    Would you like to get started?
  </div>
</div>

CSS

:root{
  --char-speed: 0.06s;
  --caret-width: 2px;
}

/* container */
.type-wrap{
  width: 250px;
  padding: 20px;
  background: #fff;
  color: #000;
  border-radius: 8px;
  font-family: monospace;
}

/* line basics */
.line{
  display:inline-block;
  overflow:hidden;
  white-space:nowrap;
  margin:6px 0;
  position:relative;
  padding-right:6px;

   
}

/* typing animation */
.line.typing{
  width:0ch;
  animation: typing steps(var(--chars)) forwards;
  animation-duration: calc(var(--chars) * var(--char-speed));
  animation-delay: var(--delay);
}

/* caret */
.line::after{
  content:"";
  position:absolute;
  right:0;
  top:0;
  width:var(--caret-width);
  height:1.2em;
  background:currentColor;

  /* caret blinks while typing */
  animation: blink 0.8s steps(1) infinite;
}

/* When typing is done, caret disappears */
.line.typing{
  animation-fill-mode: forwards;
}

/* caret removal animation scheduled after typing finishes */
.line.typing::after{
  animation: blink 0.8s steps(1) infinite, hide-caret 0s forwards;
  animation-delay: 0s, calc(var(--delay) + (var(--chars) * var(--char-speed)));
}

/* keyframes */
@keyframes typing{ to{ width:100%; } }
@keyframes blink{ 50%{ opacity:0; } }
@keyframes hide-caret{ to{ opacity:0; } }