making text appear
line by line
meow :3
this is the setup i use on my homepage for my animated svg cat pawllie. i think it is pretty neat :>
i wanted to have the text to appear line by line and letter by letter.
i also wanted some control over the animation speed of each line. the underlying idea for that
is to animate the width of each line, one line after the other and to add some parameters for easy reusability.
keep in mind that this is a lot easier (and makes more sense) with a monospace font, so make sure you use one.
lets first make a basic speech bubble.
<style>
speech-bubble {
/* monospace font of your choice */
font-family: monospace, monospace;
display: block;
width: fit-content;
outline: solid white 2px;
outline-offset: 8px;
border-radius: 10px;
margin: 60px;
padding: 5px 10px;
p {
white-space: nowrap;
overflow: hidden;
margin: auto;
width: 100%;
}
}
</style>
<speech-bubble>
<p>line one</p>
<p>and this is the second line!</p>
</speech-bubble>
line one
and this is the second line!
looking good, now the animation.
<style>
@keyframes type {
from {
width: 0;
visibility: visible;
}
to {
visibility: visible;
}
}
p {
visibility: hidden;
animation: type 2s linear forwards;
}
</style>
line one
and this is the second line!
this looks nothing like what we want, so lets get fancy.
first of all, we want our text element to end up at the exact width that the text takes up, so lets calculate that.
lets also use the :nth-child() selector to select our lines.
now we can also delay our second line to appear after our first one.
<style>
speech-bubble {
--l1-chars: 8;
--l2-chars: 28;
:nth-child(1){
width: calc(var(--l1-chars) * 1ch);
animation: type 2s linear forwards;
}
:nth-child(2){
width: calc(var(--l2-chars) * 1ch);
animation: type 2s 2s linear forwards;
}
/* add however many you need for your lines */
}
</style>
line one
and this is the second line!
there are still a few problems with this.
lets first make sure the speech bubble doesnt scale with the text.
both lines also take the same time to appear, lets address that by making the animation duration depend on how many characters a line has.
<style>
speech-bubble {
width: max(calc(var(--l1-chars) * 1ch), calc(var(--l2-chars) * 1ch));
--l1-chartime: .06;
--l2-chartime: .06;
--l1-dur: calc(var(--l1-chartime) * var(--l1-chars) * 1s);
--l2-dur: calc(var(--l2-chartime) * var(--l2-chars) * 1s);
:nth-child(1){
animation: type var(--l1-dur) linear forwards;
}
:nth-child(2){
animation: type var(--l2-dur) 2s linear forwards;
}
}
</style>
line one
and this is the second line!
we are getting close, now lets make sure that the characters actually appear one by one and fix that awkward delay in between lines.
<style>
speech-bubble {
--l1-delay: 0s;
--l2-delay: calc(var(--l1-delay) + var(--l1-dur) + .15s);
:nth-child(1){
animation: type var(--l1-dur) var(--l1-delay) steps(var(--l1-chars), end) forwards;
}
:nth-child(2){
animation: type var(--l2-dur) var(--l2-delay) steps(var(--l2-chars), end) forwards;
}
}
</style>
line one
and this is the second line!
now the whole code looks like this:
<style>
speech-bubble {
font-family: monospace, monospace;
display: block;
position: relative;
width: max(calc(var(--l1-chars) * 1ch), calc(var(--l2-chars) * 1ch));
outline: solid black 2px;
outline-offset: 8px;
border-radius: 10px;
margin: 60px;
p {
white-space: nowrap;
visibility: hidden;
overflow: hidden;
margin: auto;
}
--l1-chars: 8;
--l2-chars: 28;
--l1-chartime: .06;
--l2-chartime: .06;
--l1-dur: calc(var(--l1-chartime) * var(--l1-chars) * 1s);
--l2-dur: calc(var(--l2-chartime) * var(--l2-chars) * 1s);
--l1-delay: 0s;
--l2-delay: calc(var(--l1-delay) + var(--l1-dur) + .15s);
:nth-child(1){
width: calc(var(--l1-chars) * 1ch);
animation: type var(--l1-dur) var(--l1-delay) steps(var(--l1-chars), end) forwards;
}
:nth-child(2){
width: calc(var(--l2-chars) * 1ch);
animation: type var(--l2-dur) var(--l2-delay) steps(var(--l2-chars), end) forwards;
}
}
@keyframes type {
from {
width: 0;
visibility: visible;
}
to {
visibility: visible;
}
}
</style>
<speech-bubble>
<p>line one</p>
<p>and this is the second line!</p>
</speech-bubble>
you can now add support for more lines as needed by following the pattern, and if you want multiple speech bubbles you can override their --lx-chars and --lx-chartime parameters as needed.
<speech-bubble style="--l1-chars: 36; --l2-chars: 22; --l2-chartime: .03">
<p>you just have to override some stuff<p>
<p>and change the text :3<p>
<!-- reload to replay -->
</speech-bubble>
you just have to override some stuff
and change the text :3
thanks for reading, i hope it was helpful. now go and make something!
and send me an email at q@crim.in, id be happy to hear any feedback you have, really. i might put a kind of comments section here, similar to my hi page.