Skip to main content

Make a kinetic typography video with CSS

This article first appeared in issue 234 of .net magazine – the world's best-selling magazine for web designers and developers.

  • Download the tutorial files here

Kinetic typography is a popular way to add impact to a song or audio clip by accentuating the lyrics or script to emphasise phrases, build suspense or help tell a story. The usual method is to set type in Photoshop or Illustrator and use After Effects or Apple Motion to animate words, revealing them in time to the music.

In this tutorial, we’ll use kinetic typography to create a simple conceptual art piece, timed to a song provided by power pop band, Be Like Pablo. Rather than using After Effects, we’ll take advantage of CSS3 animations and transitions to create the piece with standard web tools: HTML5 and CSS3 for the animation and audio and a smattering of JavaScript (we’re using jQuery but you could use straight JS if you prefer) to add classes to various elements at appropriate times.

As browsers have started to fully implement the W3C recommendations for CSS, it’s fairly straightforward to make this project work in all major browsers including Firefox, Chrome, IE10, Opera and Safari. But to simplify things we’ll target WebKit-based browsers only, focusing on Chrome as our primary testbed.

Getting started

The first stage in a kinetic typography project is to identify audio to work with. We’ve permission to use Be Like Pablo’s song, Love is for the Living, which you’ll find an MP3 of in the tutorial files. We’ve transcribed the lyrics and saved them in a text document; they’ll be used to create our basic page markup. If you’re using your own audio, ensure you’ve transcribed the words into a text file.

The HTML for our design is going to be a simple set of div tags, one per line (or section) of text. Within each line, we’ve subdivided individual words by wrapping them in a span tag. This will allow us to use CSS to target each word in turn, revealing it at the right time and applying special effects to help tell the story. Look at our markup below to get a feel for how it should look:

<body> <div id="layout"> <div class="verse" id="verse1"> <div class="line"><span>Your</span> <span>life</span> <span>was</span> <span>not</span> <span>complete</span></div> <div class="line"><span>And</span> <span>for</span> <span>some</span> <span>reason</span> <span>I <strong>believed</strong></span></div> <div class="line"><span>I</span> <span>could</span> <span>colour</span> <span>in</span> <span>your</span> <span>felt-tip</span> <span>tears</span> <span>with</span> <span>imagine</span> <span>stationery</span></div> <div class="line"><span>So</span> <span>I</span> <span>cut</span> <span>around</span> <span>your</span> <span>lines</span></div> <div class="line"><span>And</span> <span>I</span> <span>super</span><span>-</span><span>glued</span> <span>our</span> <span>lives</span></div> <div class="line"><span>And</span> <span>if</span> <span>love</span> <span>is</span> <span>for</span> <span>the</span> <span>living</ span> <span>baby</span></div> <div class="line"><span>You</span> <span>must</span> <span>be</span> <span>alive</span></div> <div class="line"><span>And</span> <span>I</span> <span>know</span> <span>I</span> <span>dream</span> <span>in</span> <span>colour</span></div> <div class="line"><span>But</span> <span>my</span> <span>life</span> <span>is</span> <span>black</span> <span>and</span> <span>white</span></div> <div class="line"><span>It</span> <span>wasn't</span> <span>love</span> <span>...</span></div> </div> </div></body>

We’ve wrapped the verse inside a div with an ID of verse1, and created an overall container we’ve named layout. The layout div will be used to create the window we’ll see the final motion piece through; verse will be our camera dolly, moving behind the layout div to reveal different elements as the song plays.

Creating a layout

The key element in a kinetic typography piece is word layout. Size, position and relationship between them help tell the story, and add drama; consider reveals and final placement, ensuring you look at the aesthetic treatment throughout. We’ve chosen a simple layout to illustrate general principles, but still included some ideas based on the imagery created by the lyrics. We’ve picked a few key phrases to emphasise in the first verse, and used CSS to position these across our verse1 div using absolute positioning. Try to think around the words and phrases you’re setting, especially if they conjure an image as you read them.

The song we’re using here has plenty to offer as inspiration; for example around lines 4 and 5 where the lyrics read, “So I cut around your lines/And I super-glued our lives”. This lends itself well to a visual metaphor, so we’ve opted to set both lyrics inside a box with dashed lines (suggesting it could be cut out).

The first phrase is set to have a line break half way through by limiting the width of the containing div; the second is positioned between the two lines formed by the first, and is set to use a smaller version of the font. This suggests an interplay between the two lyrics, and with a bit of animation later we can cement the metaphor, separating the dashed box from the background and using the second phrase to bring together the lines of the first. The CSS is here:

#verse1 .line:nth-of-type(4) { font-size: 21.5em; position: absolute; top: 1500px; left: 500px; width: 1500px; padding: 150px; border: 25px dashed #fff;}#verse1 .line:nth-of-type(5) { position: absolute; font-size: 5em; width: 2500px; top: 1900px; left: 775px;}

Note we’re using the :nth-of-type(x) selector in our style sheet to target specific lines. This enables us to keep our HTML clean without unnecessary markup and classes/IDs. We can use the same approach to target specific <span> elements within each line as shown in the CSS below, which defines a rotation for the words in the second line of the verse:

#verse1 .line:nth-of-type(2) span { display: block; -webkit-transform:rotate(30deg) translateX(-500px);}

Repeat the process for each line of the verse, rotating and positioning words and lines to create a coherent whole. Try to vary the size and positioning of elements; make it exciting, but provide breathing opportunities between showcase elements in your layout and design. You can use different fonts to create moods or convey different voices within a piece of audio.

Setting up special effects

Some of your layout will call for special animation effects. For example, in the lines we looked at earlier we wanted to position the second line in between the words of the first line, and have the second line pull the first together like glue. We can achieve this using a combination of the CSS transition property, and the line-height property to reduce the leading between two lines. By assigning a value to the transition property for all span tags, we can ensure that every special effect we add will automatically be animated:

.line { line-height: 1em; -webkit-transition: all 0.8s linear;}

This sets all the lines of the verses to animate any altered properties over 0.8 seconds, and presets the line-height at 1em (relative to their font size). Next, we create a special effect class that sets the line height to 0.5em:

.halfleading { line-height: 0.5em;}

Later on, we’ll apply the halfleading class to line 4 at the right time to have it animate as if being glued together by line 5.

We can apply the same methodology to the individual span tags, hiding them by default, and setting up a transition property to animate them into view when they have the class of active applied to them:

.line span { opacity: 0; color: #fff; text-shadow: 0px 0px 5px #699; -webkit-transition: all 0.1s linear;}

We’ve created seven different special effects for our piece, including the example above. Several of these use a new CSS property – animation keyframes.

Animation keyframes and camera moves

At the end of the first verse the lyric reads, “It wasn’t love …”. We’ve chosen to treat the word ‘love’ with a beating heart effect to draw attention to it. The easiest way to get this effect is to use animation keyframes to define the size of the word over time, having it pulse in a regular fashion. We start off by defining our animation keyframes, ranging between 0% and 100% of the animation:

@-webkit-keyframes pulse { 0% { -webkit-transform: scale(1); } 60% { -webkit-transform: scale(1.2); } 75% { -webkit-transform: scale(0.9); } 100% { -webkit-transform: scale(1); }}

Next we’ll apply this animation using a class, which we can assign to the word ‘love’ at the right time:

.pulse { display: inline-block; -webkit-animation:pulse 0.4s infinite;}

We’ve got our type set and effects created, but need to set up the window, and assign the position the verse div will occupy to reveal the right bit of action for each line. The .line1 class positions the div so the first line is visible through the window; line2 shifts the position of the verse div to reveal the second line. We’re also altering the verse div’s scale and rotation to build drama and motion. Go through each line, creating styles to place the div behind the window:

/* Camera Moves */#verse1.line1 { -webkit-transform: scale(2) translateX(-400px) translateY(-450px);}#verse1.line1.word2 { -webkit-transform: scale(2) translateX(-500px) translateY(-450px);}

If you need, add secondary classes to animate the camera during individual lines. We’ve done this using the naming convention .lineX.wordY to indicate when the position should change. Once you’ve created a class for each camera move required, it’s time to create a script to assign the styles at the right time.

Applying the classes and creating the animation

The final bit of work needed to make the animation work is to time the classes so the words are revealed at the appropriate point of the audio clip. There are various ways to achieve this, but we’ve opted to use jQuery and take advantage of the .animation queue to stack up our elements. We’ve created two utility functions. The first adds a class to the specified element after a set period of time since the last class was applied to it; the second removes a class.

// Add the class after a specified delay. This is a bit of a hack!function fire(selector,classname, waittime) { $(selector).delay(waittime).animate({1:1},1,function(){$(this).addClass(classname);});}// Remove the class after a specified delay. This is a similar hack!function killclass(selector,classname,waittime) { $(selector).delay(waittime).animate({1:1},1,function(){$(this).removeClass(classname);});

Next we need to grab our audio element and set it playing. We need a direct reference to the audio to use the built-in play() function, so we’ll grab it using getElementById rather than returning a jQuery object:

audio = document.getElementById('song');;

Last, we need to call our utility functions in sequence, applying and removing classes to call the CSS transitions and animations. Remember the jQuery animation queue is stacked relative to the last time an animation was run on that element, so the first time you add a class to a given element it’s timed relative to the start of the audio clip. Subsequent addition or removal of classes is relative to the previous addition or removal. Times are in milliseconds.

fire("#verse1","line1",0);fire("#verse1 .line:eq(0) span:eq(0)","active",4000);fire("#verse1","word2",4200);....// Reset the position of verse1killclass("#verse1","line1",1200);

Continue working your way through each line and span, testing regularly to make sure you time your classes to match the audio correctly.

Words: Sam Hampton-Smith

Thanks to Chris Mills for his peer review of this tutorial

The Creative Bloq team is made up of a group of design fans, and has changed and evolved since Creative Bloq began over a decade ago. The current website team consists of five people: Editor Kerrie Hughes, Deputy Editor Rosie Hilder, Deals Editor Beren Neale, Senior News Editor Daniel Piper, and Staff Writer Amelia Bamsey. The 3D World and ImagineFX magazine teams also pitch in, ensuring that content from 3D World and ImagineFX is represented on Creative Bloq.