How to Create a Typewriter Text with Pure CSS
You'll agree that a text that looks like it is being typed across the screen looks quite attractive. Did you know that you can apply a typewriter effect to your text by using pure CSS? Now we are going to do that together, step by step!
Create HTML
<div class="typewriter">
<h1>Once upon a time.</h1>
</div>
Add CSS
- To ensure that each character has the same width and to make the transition between letters feel like being physically typed, set the font-family property to “monospace”.
- Use the letter-spacing to define the space between letters and add a margin.
- Set the overflow property to its “hidden” value to hide the content, which exceeds the width of the element.
- Prevent the text from splitting into two lines by using the white-space property with the “nowrap” value.
- Add the border-right property. That will be a blinking cursor at the end of the text. The blinking effect will be created by applying animation to our border.
- Add animation with the animation property. You are free to choose the length of time and the number of steps.
- Define keyframes for the animation. The first one will be for the typing, another one for the cursor.
.typewriter h1 {
font-family: monospace;
letter-spacing: .17em;
margin: 0 auto;
overflow: hidden;
white-space: nowrap;
border-right: .17em solid pink;
animation: typing 3.5s steps(30, end), blinking-cursor .5s step-end infinite;
}
@keyframes typing {
from {
width: 0
}
to {
width: 100%
}
}
@keyframes blinking-cursor {
from,
to {
border-color: transparent
}
50% {
border-color: pink;
}
}
Now it’s high time we put it all together and see the result.
Example of creating a typewriter text:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
.typewriter h1 {
font-family: monospace;/* Web-safe typewriter-like font */
overflow: hidden;/* Ensures the content is not revealed until the animation */
border-right: .17em solid pink;/* The typewriter cursor */
white-space: nowrap;/* Keeps the content on a single line */
margin: 0 auto;/* Gives that scrolling effect as the typing happens */
letter-spacing: .17em;/* Adjust as needed */
animation: typing 3.5s steps(30, end), blinking-cursor .5s step-end infinite;
}
/* The typing effect */
@keyframes typing {
from {
width: 0
}
to {
width: 100%
}
}
/* The typewriter cursor effect */
@keyframes blinking-cursor {
from,
to {
border-color: transparent
}
50% {
border-color: pink;
}
}
</style>
</head>
<body>
<div class="typewriter">
<h1>Once upon a time...</h1>
</div>
</body>
</html>
Example of creating a typewriter text with the animation, animation-fill-mode, and animation-delay properties:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
.content p {
border-right: .15em solid orange;
font-family: "Courier";
font-size: 14px;
white-space: nowrap;
overflow: hidden;
}
.content p:nth-child(1) {
width: 7.3em;
-webkit-animation: type 2s steps(40, end);
animation: type 2s steps(40, end);
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
.content p:nth-child(2) {
width: 11.5em;
opacity: 0;
-webkit-animation: type2 2s steps(40, end);
animation: type2 2s steps(40, end);
-webkit-animation-delay: 2s;
animation-delay: 2s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
.content p:nth-child(3) {
width: 7.3em;
opacity: 0;
-webkit-animation: type3 5s steps(20, end), blink .5s step-end infinite alternate;
animation: type3 5s steps(20, end), blink .5s step-end infinite alternate;
-webkit-animation-delay: 4s;
animation-delay: 4s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
@keyframes type {
0% {
width: 0;
}
99.9% {
border-right: .15em solid #82B533;
}
100% {
border: none;
}
}
@-webkit-keyframes type {
0% {
width: 0;
}
99.9% {
border-right: .15em solid #82B533;
}
100% {
border: none;
}
}
@keyframes type2 {
0% {
width: 0;
}
1% {
opacity: 1;
}
99.9% {
border-right: .15em solid #82B533;
}
100% {
opacity: 1;
border: none;
}
}
@-webkit-keyframes type2 {
0% {
width: 0;
}
1% {
opacity: 1;
}
99.9% {
border-right: .15em solid #82B533;
}
100% {
opacity: 1;
border: none;
}
}
@keyframes type3 {
0% {
width: 0;
}
1% {
opacity: 1;
}
100% {
opacity: 1;
}
}
@-webkit-keyframes type3 {
0% {
width: 0;
}
1% {
opacity: 1;
}
100% {
opacity: 1;
}
}
@keyframes blink {
50% {
border-color: transparent;
}
}
@-webkit-keyframes blink {
50% {
border-color: tranparent;
}
}
</style>
</head>
<body>
<div class="content">
<p>
Lorem Ipsum
</p>
<p>
Lorem ipsum is simply a false texte...
</p>
<p>
Lorem Ipsum
</p>
</div>
</body>
</html>
Example of creating a typewriter text with a styled cursor:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
body {
padding: 40px;
background-color: #666666;
}
#main {
height: 40px;
white-space: nowrap;
overflow: hidden;
font-family: 'Source Code Pro', monospace;
font-size: 28px;
color: rgba(255, 255, 255, .70);
position: relative;
}
#border {
border-bottom: solid 3px rgba(0, 255, 0, .75);
position: absolute;
right: -7px;
width: 20px;
}
/* Animation */
#main {
animation: animated-text 2s steps(30, end) 1s 1 normal both
}
#border {
animation: animated-cursor 600ms steps(30, end) infinite;
}
/* text animation */
@keyframes animated-text {
from {
width: 0;
}
to {
width: 480px;
}
}
/* cursor animations */
@keyframes animated-cursor {
from {
border-bottom-color: rgba(0, 255, 0, .75);
}
to {
border-bottom-color: transparent;
}
}
</style>
</head>
<body>
<div id="main">
Once upon a time...
<div id="border"></div>
</div>
</body>
</html>
Example of adding a cursor without a typing effect:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
body {
padding: 40px;
background-color: #8EBF43;
}
p {
white-space: nowrap;
overflow: hidden;
font-family: 'Source Code Pro', monospace;
font-size: 28px;
color: rgba(255, 255, 255, .70);
}
/* Animation */
p {
animation: animated-text 3s steps(30, end) 1s 1 normal both;
}
/* text animation */
@keyframes animated-text {
from {
width: 0;
}
to {
width: 472px;
}
}
</style>
</head>
<body>
<p>This text doesn’t have a typewriter effect.</p>
</body>
</html>
Example of adding a smooth typing effect with a blinking cursor:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
body {
padding: 40px;
background-color: #c13b17;
}
p {
border-right: solid 5px rgba(255, 255, 255, .75);
white-space: nowrap;
overflow: hidden;
font-family: 'Source Code Pro', monospace;
font-size: 28px;
color: rgba(255, 255, 255, .70);
}
/* Animation */
p {
animation: animated-text 4s linear 1s 1 normal both, animated-cursor 600ms linear infinite;
}
/* text animation */
@keyframes animated-text {
from {
width: 0;
}
to {
width: 456px;
}
}
/* cursor animations */
@keyframes animated-cursor {
from {
border-right-color: rgba(255, 255, 255, .75);
}
to {
border-right-color: transparent;
}
}
</style>
</head>
<body>
<p>To be or not to be</p>
</body>
</html>
Example of creating a typewriter text moving to the left:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
body {
padding: 40px;
background-color: #121212;
}
p {
border-right: solid 3px rgba(0, 255, 0, .75);
white-space: nowrap;
overflow: hidden;
font-family: 'Source Code Pro', monospace;
font-size: 28px;
color: rgba(255, 255, 255, .70);
position: absolute;
right: 10px;
}
/* Animation */
p {
animation: animated-text 4s steps(17, end) 1s 1 normal both, animated-cursor 600ms steps(17, end) infinite;
}
/* text animation */
@keyframes animated-text {
from {
width: 0;
}
to {
width: 286px;
}
}
/* cursor animations */
@keyframes animated-cursor {
from {
border-right-color: rgba(0, 255, 0, .75);
}
to {
border-right-color: transparent;
}
}
</style>
</head>
<body>
<p>I am being typed.</p>
</body>
</html>
Example of adding a typewriter effect with alternating text:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
body {
background-color: #71718c;
color: #ffffff;
font-size: 100px;
}
h1 {
font-size: 30px;
}
.text-1 {
animation: text1;
}
.text-2 {
animation: text2;
}
.text-1,
.text-2 {
overflow: hidden;
white-space: nowrap;
display: inline-block;
position: relative;
animation-duration: 20s;
animation-timing-function: steps(25, end);
animation-iteration-count: infinite;
}
.text-1::after,
.text-2::after {
content: "|";
position: absolute;
right: 0;
animation: caret infinite;
animation-duration: 1s;
animation-timing-function: steps(1, end);
}
@keyframes text2 {
0%,
50%,
100% {
width: 0;
}
60%,
90% {
width: 21.2em;
}
}
@keyframes text1 {
0%,
50%,
100% {
width: 0;
}
10%,
40% {
width: 17em;
}
}
@keyframes caret {
0%,
100% {
opacity: 0;
}
50% {
opacity: 1;
}
}
</style>
</head>
<body>
<h1>
<span class="text-1">I am a great heading for your static web page</span>
<span class="text-2">Really? And this is made without JavaScriipt?</span>
</h1>
</body>
</html>