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