Rotating text with CSS animations

July 12, 2019

I’ve been toying with different ideas for how I can describe the work that I do to people visiting my website. One idea that I had involved rotating a single word or phrase inside of a sentence to list the different qualities of my work. Here’s a quick tutorial of the prototype that I built for how this effect might be achieved using HTML and CSS.

Here’s an example of what we will be building:

See the Pen Rotating text with CSS animations by Keenan Payne (@keenanpayne) on CodePen.

Writing copy

Before writing any code, I knew that I wanted to have the following headline on my website:

I'll make your website... [insert adjective here]

For my adjectives, I made a list of what I wanted to rotate through:

  • beautiful
  • maintainable
  • perfect

Having a rough idea of the copy that I will be using helps me understand what the markup will need to look like as I’m coding.

Marking up the DOM

After writing up my copy, I started marking up the DOM. Marking up the DOM before embarking on styling allows me to define the semantics of how this code should be written, then write the styles to fit these semantics.

<p class="rotatingText">
  I'll make your website&hellip;

  <span class="rotatingText-adjective">beautiful</span>
  <span class="rotatingText-adjective">maintainable</span>
  <span class="rotatingText-adjective">perfect 👌</span>
</p>

Basic styles

After marking up the DOM, I styled my text so that I could get an understanding of how the styles would be changing as the animation runs.

.rotatingText {
  font-family: 'Georgia', serif;
  font-style: italic;
  font-size: 18px;
  text-align: center;
}

.rotatingText-adjective { 
  font-family: 'Open Sans', sans-serif;
  font-size: 50px;
  font-style: normal;
  font-weight: 700;
  left: 0;
  margin-bottom: 0;
  margin-top: 50px;
  position: absolute;
  right: 0;
  text-align: center;
  text-transform: uppercase;
  top: 0;
}

See the Pen Rotating text with CSS animations [step 1] by Keenan Payne (@keenanpayne) on CodePen.

Adding the animation

Our headline is starting to come together after adding some styles. Now it’s time to tackle the animation.

Toggling visibility

The first step in the animation is ensuring that all of the adjectives in our headline are hidden until the animation runs. Hiding things on the web can be done in many different ways, and it’s important that our approach will not impact the accessibility of our content for visitors using screen readers or other assistive technologies. For this project, the visibility of our content will change by toggling the opacity property on the .rotatingText-adjective class.

.rotatingText-adjective { 
  font-family: 'Open Sans', sans-serif;
  font-size: 50px;
  font-style: normal;
  font-weight: 700;
  left: 0;
  margin-bottom: 0;
  margin-top: 50px;
* opacity: 0;
  position: absolute;
  right: 0;
  text-align: center;
  text-transform: uppercase;
  top: 0;
}

Hiding content on the web is tricky, I recommend reading Scott O’Hara’s article on inclusively hiding content, as well as Zell Liew’s article on using opacity to hide content.

With the adjectives hidden, we can write an animation using CSS keyframes that toggle the opacity property.

@keyframes rotate {
  0% {
    opacity: 0;
  }
  
  20%, 80% {
    opacity: 1;
  }
  
  100% {
    opacity: 0;
  }
}

We then add this animation to each of our adjectives so that it runs one after another. This effect is accomplished by staggering the values in the animation-delay property.

.rotatingText-adjective:nth-of-type(1) {
  animation-name: rotate;
  animation-duration: 1.5s;
  animation-delay: .5s;
}

.rotatingText-adjective:nth-of-type(2) {
  animation-name: rotate;
  animation-duration: 1.5s;
  animation-delay: 1.75s;
}

.rotatingText-adjective:nth-of-type(3) {
  animation-name: rotate;
  animation-duration: 1.5s;
  animation-delay: 3s;
}

See the Pen Rotating text with CSS animations [step 2] by Keenan Payne (@keenanpayne) on CodePen.

Finessing the last adjective

The animation is successfully running! However, our last adjective slides away with the rest, so we’ll need to make some adjustments so that it stays on the screen. To do this, we can create a set of keyframes specifically for our last animation:

@keyframes rotate-last {
  0% {
    opacity: 0;
  }
  
  100% {
    opacity: 1;
  }
}

We then apply this animation to our last adjective:

.rotatingText-adjective:nth-of-type(3) {
* animation-name: rotate-last;
  animation-duration: 1.5s;
  animation-delay: 3s;
* animation-fill-mode: forwards;
}

Also note that I added the declaration animation-fill-mode: forwards which indicates that the animation should stop on the last frame of the animation after running.

Moving the text

Now that the visibility of the text is toggled, we can update our keyframes to create the rotating effect that we want:

@keyframes rotate {
  0% {
    opacity: 0;
    transform: translate3d(0, 50px, 0);
  }
  
  20%, 80% {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
  
  100% {
    opacity: 0;
    transform: translate3d(0, -25px, 0);
  }
}

This is done by animating the translate3d() value inside of the transform property. The translate3d() value accepts three arguments: x, y, and z-axis positions. Because our text should be moving from the bottom up, we are only concerned with updating the y-axis.

To give our text the effect of moving from the bottom up, we push it down on the y-axis fifty pixels. We move our text into position by resetting our y-axis to zero. Finally, we slide our text out of place by negative twenty-five pixels on the y-axis. This gives us the rotating effect that we want.

We will use a slightly modified version of this code for our last adjective. Because our last adjective should stay in place, we can omit the declaration that moves our adjective negative twenty-five pixels.

@keyframes rotate-last {
  0% {
    opacity: 0;
    transform: translate3d(0, 50px, 0);
  }
  
  50%, 100% {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

With that, we have a fully functional rotating headline just like we wanted:

See the Pen Rotating text with CSS animations [step 3] by Keenan Payne (@keenanpayne) on CodePen.

Our final code looks like this:

HTML

<p class="rotatingText">
  I'll make your website&hellip;

  <span class="rotatingText-adjective">beautiful</span>
  <span class="rotatingText-adjective">maintainable</span>
  <span class="rotatingText-adjective">perfect 👌</span>
</p>

CSS

.rotatingText {
  font-family: "Georgia", serif;
  font-style: italic;
  font-size: 18px;
  text-align: center;
}

.rotatingText-adjective {
  font-family: "Open Sans", sans-serif;
  font-size: 50px;
  font-style: normal;
  font-weight: 700;
  left: 0;
  margin-bottom: 0;
  margin-top: 50px;
  opacity: 0;
  position: absolute;
  right: 0;
  text-align: center;
  text-transform: uppercase;
  top: 0;
}

.rotatingText-adjective:nth-of-type(1) {
  animation-name: rotate;
  animation-duration: 1.5s;
  animation-delay: 0.5s;
}

.rotatingText-adjective:nth-of-type(2) {
  animation-name: rotate;
  animation-duration: 1.5s;
  animation-delay: 1.75s;
}

.rotatingText-adjective:nth-of-type(3) {
  animation-name: rotate-last;
  animation-duration: 1.5s;
  animation-delay: 3s;
  animation-fill-mode: forwards;
}

@keyframes rotate {
  0% {
    opacity: 0;
    transform: translate3d(0, 50px, 0);
  }
  
  20%, 80% {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
  
  100% {
    opacity: 0;
    transform: translate3d(0, -25px, 0);
  }
}

@keyframes rotate-last {
  0% {
    opacity: 0;
    transform: translate3d(0, 50px, 0);
  }
  
  50%, 100% {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

Wrap-up

Animating the translate3d() value on the transform property is a simple but powerful way to move elements on a page. This same property can be used to move elements along all three axes, offering many different animation possibilities. Did you like this? You can hire me!

Hire me to  build a website improve your website build a design system do anything on the web

I'm currently available for freelance development and consulting for projects of all shapes and sizes. Get in touch and let's see if I can be of service to you.