DEV Community

Cover image for Throwing around text - Kinetic typography part 1: A chilly warm-up πŸ“ ️ πŸš€
Pascal Thormeier
Pascal Thormeier

Posted on • Updated on

Throwing around text - Kinetic typography part 1: A chilly warm-up πŸ“ ️ πŸš€

Part 1 of a new series! Let's build some kinetic typography with HTML, CSS and JS!

So, what's this about?

I recently saw a video by the amazing Will Paterson about some 6 design trends in 2022. At timestamp 5:44 he talks about so-called "kinetic typography". That immediately caught my full attention. Partially because I like stuff that moves (weee!), the other part of me asked itself "can I build that?"

Most kinetic typography I found is done with After Effects, so it's videos and gifs, mostly. Kinetic typography on the web, on the other hand, is not much of a thing just yet, I might guess. I'm not really talking about text that appears line by line with a fade, though. Even though this can be considered kinetic typography, it's been done by at least a few dozens of websites since ages already. No, I'm talking big here. Whirling, flying, swimming, falling and falling apart, all sorts of things.

Today, I'm going to rebuild the first of ten video examples of kinetic typography with HTML and CSS. I'm allowed to use some physics library for future ones, maybe, let's see. (I will not build an entire 2D physics engine from scratch, that would be missing the point.)

So, let's try to find some good example video first. I'll start out with something more simple for a warm-up in this post and keep the most complex stuff for the grande finale!

Disclaimer: Due to the moving and sometimes flashy nature of kinetic typography, I will only ever show single frames of gifs and will not make the coded examples play automatically. I don't want anyone to feel sick or bad because of my content.

A chilly warm-up

A Popular Search Engineβ„’ yields tons upon tons of examples. It's really hard to chose, actually, but let's go with with this COOL example from this listicle on invisionapp.com:

The word "COOL" bouncing in an accordion effect, but only a single frame of the animation is shown.

(Click here for the full gif animation. Minor trigger warning, though: Some people might experience motion sickness when looking at this image too long. It's not really flashy, but moving a lot.)

Mind you, this is a warm-up excersise. So, let's get going.

Step one is to code out the text in a more or less accessible way. We need to animate each character individually, so we basically need to split them into separate HTML elements. To still make this accessible to screen readers, we'll use aria attributes. We need each letter several times in order to make them appear with this black and white gradient behind the actual letter.

<div class="bouncy">
  <h1 aria-label="Chilly">
    <span aria-hidden="true" class="text-container">
      <span class="letter">
        <span class="front-letter">C</span>
        <span class="back-letter">C</span>
        <span class="back-letter">C</span>
        <!-- Repeat this a few more times -->
      </span>
      <span class="letter">
        <span class="front-letter">h</span>
        <span class="back-letter">h</span>
        <span class="back-letter">h</span>
        <!-- Repeat this a few more times -->
      </span>
      <span class="letter">
        <span class="front-letter">i</span>
        <span class="back-letter">i</span>
        <span class="back-letter">i</span>
        <!-- Repeat this a few more times -->
      </span>
      <span class="letter">
        <span class="front-letter">l</span>
        <span class="back-letter">l</span>
        <span class="back-letter">l</span>
        <!-- Repeat this a few more times -->
      </span>
      <span class="letter">
        <span class="front-letter">l</span>
        <span class="back-letter">l</span>
        <span class="back-letter">l</span>
        <!-- Repeat this a few more times -->
      </span>
      <span class="letter">
        <span class="front-letter">y</span>
        <span class="back-letter">y</span>
        <span class="back-letter">y</span>
        <!-- Repeat this a few more times -->
      </span>
    </span>
  </h1>
</div>
Enter fullscreen mode Exit fullscreen mode

Next, we need some boilerplating CSS to give this text some basic styling:

@import url('https://fonts.googleapis.com/css2?family=Bree+Serif&display=swap');

html, body {
    margin: 0;
    padding: 0;
}
.bouncy-accordion {
    height: 80vh;
    background-color: #BCAD90;
    display: flex;
    align-items: center;
    justify-content: center;
}

.bouncy h1 {
    font-family: 'Bree Serif', serif;
    font-weight: 700;
    font-size: 25vh;
    margin: 0;
    padding: 0;
    color: #fff;
    /* Works in most modern browsers */
    -webkit-text-stroke: 5px #000;
    text-transform: uppercase;
    letter-spacing: -30px;
}
Enter fullscreen mode Exit fullscreen mode

Let's have a look:

The word "Chilly" with some serif font and a text outline.

So far so good. In the original animation, we see them bouncing up and down and doing some rotation. So, next, we'll add some keyframes to do exactly that:

@keyframes bouncy {
    0% {
        transform: translateY(-20%) rotate(6deg);
    }
    50% {
        transform: translateY(20%) rotate(-6deg);
    }
    100% {
        transform: translateY(-20%) rotate(6deg);
    }
}
Enter fullscreen mode Exit fullscreen mode

This translates the letters up and down and rotates them, giving them a little more life. When we look at the example, there seems to be a bit of a delay for each letter. They don't animate in unison. The letters behind them (the black and white striping) also has some delay, but a different timing. To make things a little bit simpler for us, we define some custom CSS attribute to deal with the animation delay:

.bouncy .letter:nth-child(1) {
    --base-delay: 0ms;
}
.bouncy .letter:nth-child(2) {
    --base-delay: 200ms;
}
.bouncy .letter:nth-child(3) {
    --base-delay: 400ms;
}
.bouncy .letter:nth-child(4) {
    --base-delay: 600ms;
}
.bouncy .letter:nth-child(5) {
    --base-delay: 800ms;
}
.bouncy .letter:nth-child(6) {
    --base-delay: 1000ms;
}
Enter fullscreen mode Exit fullscreen mode

Next up, we position all of the letters such that the same letters (.back-letter) are overlapped by their .front-letter. We also add the animations:

.bouncy .text-container {
    display: block;
    position: relative;
}
.bouncy .letter {
    display: inline-block;
    position: relative;
}
.bouncy .front-letter,
.bouncy .back-letter {
    display: inline-block;
    animation: bouncy 2.5s infinite ease-in-out;
}
.bouncy .front-letter {
    position: relative;
    z-index: 5;
    animation-delay: var(--base-delay);
}
.bouncy .back-letter {
    position: absolute;
    left: 0;
}
Enter fullscreen mode Exit fullscreen mode

And now, for the final touch, we add colors and the actual animation delay to the back letters:

.bouncy .back-letter:nth-child(even) {
    /* Keeps the size of the text the same */
    -webkit-text-stroke: 5px #fff;
    color: #fff;
}
.bouncy .back-letter:nth-child(odd) {
    -webkit-text-stroke: 5px #000;
    color: #000;
}

.bouncy .back-letter:nth-child(2) {
    animation-delay: calc(var(--base-delay) + 100ms);
    z-index: 9;
}
.bouncy .back-letter:nth-child(3) {
    animation-delay: calc(var(--base-delay) + 200ms);
    z-index: 8;
}
.bouncy .back-letter:nth-child(4) {
    animation-delay: calc(var(--base-delay) + 300ms);
    z-index: 7;
}
.bouncy .back-letter:nth-child(5) {
    animation-delay: calc(var(--base-delay) + 400ms);
    z-index: 6;
}
/* Repeat this a few more times */
Enter fullscreen mode Exit fullscreen mode

Et voila, a finished animation:

And that's it for the warmup!


I hope you enjoyed reading this article as much as I enjoyed writing it! If so, leave a ❀️ or a πŸ¦„! Also, consider following me if you want to see how the other examples turn out! I write tech articles in my free time and like to drink coffee every once in a while.

If you want to support my efforts, you can offer me a coffee β˜• or follow me on Twitter 🐦! You can also support me directly via Paypal!

Buy me a coffee button

Top comments (0)