After the scalable one-line typewriter and the crazy "scrabble"-writer let's do another one: The multi-line typewriter.
A CSS-only solution of course:
The effect relies on using a Monospace font and knowing the number of characters. Yes, I am starting with the drawbacks but that was the price for a generic and easy-to-use code.
The HTML is very basic:
This is a <span class="type" style="--n:53">CSS only solution for a multi-line typewriter effect.</span>
A span with our text and the number of characters as a variable.
For the CSS:
.type {
font-family: monospace;
color:#0000;
background:
linear-gradient(-90deg,#00DFFC 5px,#0000 0) 10px 0,
linear-gradient(#00DFFC 0 0) 0 0;
background-size:calc(var(--n)*1ch) 200%;
-webkit-background-clip:padding-box,text;
background-clip:padding-box,text;
background-repeat:no-repeat;
animation:
b .7s infinite steps(1),
t calc(var(--n)*.3s) steps(var(--n)) forwards;
}
@keyframes t{
from {background-size:0 200%}
}
@keyframes b{
50% {background-position:0 -100%,0 0}
}
A few lines of CSS code with no hard-coded values. We only need to update the variable --n
.
How does it work?
The trick relies on background properties so as a reference I always recommend this article:
All you need to know about background-position
Temani Afif for This is Learning ・ Mar 13 '21
We have two background layers. The first layer will color the text and the second one will create the blinking caret.
The idea of the first layer is to apply a discrete animation of background-size
to create a filling effect from the first character to the last one using a gradient coloration.
Here is a step-by-step illustration to understand the trick:
The second layer is our caret. Here we will perform two animations. The first one is a background-size
animation similar to the text coloration since the caret needs to follow the text. The second one is a background-position
animation to create the blinking effect.
Another step-by-step to understand:
The width of the caret is controlled by the 5px
inside the gradient and we add a small offset (10px
) to avoid having an overlap with the text animation.
That's it! Simply imagine both layers animating at the same time and we have our CSS-only typewriter effect.
✔️ No Javascript
✔️ A basic HTML code
✔️ No complex CSS code. Less than 10 declarations and no hard-coded values
✔️ Accessible. The text is written within the HTML code (no pseudo-element, no duplicated text)
❌ Require a monospace font
⚠️ You can use any text without changing the code but you have to update one variable
Top comments (18)
Love this one, I can't spot it but on iPhone (again...damned apple) it only shows the first two lines and then stops? Is it the background clip not behaving itself?
I only think that as the cursor position works correctly, I could be wrong!
yes it's the background-clip:text working only for the first line of the span. Safari and IOS have a lot of issues with background-clip:text
so how can we do for safari and IOS.
Did you ever find a fix for this? experiencing the same issue
This one's really helpful and I will surely try this, the explanation was also great.
Hi @afif , thank you very much for this guide. It was really useful!
I'm trying to implement a version of this in a personal project, and i needed a responsive, multi-line typewriter effect, and this fits very nicely.
However, i am having a bit of a problem. I am not sure if this is a bug or me not having understood your guide well enough, but when i try to do it the steps dont seem to match the characters. Characters get chopped up weirdly.
I made a sandbox with an example implementation of my code. I tried even hardcoding the text length, the time and the text to display and the bug is still there. Its more visible on longer texts.
If you could take a look at it and see if you can spot the bug, i would really appreciate it. n.n
here's the sandbox: codesandbox.io/s/buggy-typewriter-...
You are changing the animation, this won't work. Check my code to see the background-size definition I am using. It depends on the text length
background-size:calc(var(--n)*1ch) 200%;
You need to keep this. Same for the duration, it look like this:calc(var(--n)*.3s)
Thanks for replying Afif!
I re-implemented the background and the calcs, but that was not the problem.
It turns out that the problem were my modification to the animations.
I wrote:
@keyframes typeText {
from {
background-size: 0 200%;
}
to {
background-size: 100% 200%;
}
}
and commenting out the to{} fixed it. I seem to have misunderstood what the animation does exactly.
additionally, another bug is that i was using japanese characters or emojis, which seem to not work very well with monospace fonts...
Anyways, thanks again for the typewriter effect! i love it
Hey! This is great. I have been trying to implement it on text under a tag, but I am having some difficulties. That's the best I got: codepen.io/Luca-Marco-Pappalardo/p.... Basically the link text is not animated in sequence, the other best outcome I had was for the text to remain black and not be animated at all. Any idea on how ti fix this?
So I messed around with your code as it would just print everything on a single line and not create a new line depending on the size of the window, so I added work-break: break-all to the bottom of the .type id and now it automatically prints to the next line regardless of window size. I hope this helps to improve upon your non-JS CSS typewriter creation
Respect!
Nice! Good job!
Good, how do you link the posts?
by creating a serie. You can find this setting next to the publish button
Oooh! I need to make mine a series too... next one coming this evening.
Nice, tks!
Nice. I really like this one and the whole explanation. A+.
This can be great if you use it with javascript to calculate the length of text and update the variable. The code can be simple.