Photo by Julia Caesar on Unsplash

Cascading text animations with CSS

Tricks with Jade/Pug and SASS

Some possible effects?

I honestly can’t remember where I saw the original effect that gave me this idea. It could possibly have been on a BBC website.

Regardless, it got me thinking. Can I make my title text or any text for that matter a little more interesting? Looping and CSS animation to the rescue!

For this in camp TL;DR who just want to see some code and a demo… 🎩

Cascading text effects demo written with Pug(Jade) and Stylus

What’s the idea?

We want to take a word or block of text and animate each letter with some form of entrance or animation. The difference here being that we want them to animate in sequence and not all at once.

The markup

Our animation is a little trickier so requires creating an element for each letter in our word. Example markup as follows;

<div class="cascading-text">
<span class="cascading-text__letter>J</span>
<span class="cascading-text__letter>H</span>
<span class="cascading-text__letter>E</span>
<span class="cascading-text__letter>Y</span>

If you’re using Jade/Pug, you could get away with looping your element creation, especially if a word gets a little long.

- var word = 'JHEY'
each val, index in word.split('')
.cascading-text__letter= val

The styles

For our example we are going to produce the fading entrance where each letter fades in one after the other. How do we get the letters to fade in one after the other? Use animation delays based on CSS child selectors.

This would be pretty long winded to write out in plain CSS. Using a CSS preprocessor we can use loops to take care of the heavy lifting for us.

$textHeight: 50px;
$letterSize: 25px;
$wordLength: 4;
$animationDuration: .5s;
$animationInterval: .1s;
.cascading-text {
height : $textHeight;
line-height: $textHeight;
padding : 10px;
&__letter {
font-size: $letterSize;
display : inline-block;
opacity: 0;
animation-name: fade;
@for $i from 1 through $wordLength {
&:nth-of-type(#{$i}) {
animation-delay: $animationInterval * $i;
animation-duration: $animationDuration;
animation-fill-mode: forwards;
@keyframes fade {
from {
opacity: 0;
to {
opacity: 1;

Our loop allows us to step our animation delay for each child element.

Note that we also use “animation-fill-mode: forwards;”. This is important. Using this property means that once our animation ends for each letter, the letter will remain in the end state and not revert to the state before it animated.

That’s it!

A short and sweet one today. A tidy bit of code with plenty of potential for creating some aesthetically pleasing effects!

As always, any questions or suggestions, please feel free to leave a response or tweet me 🐦!