When visiting this website you're greeted with a title that has the last word rotating through a couple of different words. You are probably thinking that some npm
library out that created this feature, but you maybe surprised that it's not the case. Instead, you'll be amazed at how little javascript and HTML you need to create this feature. Before continuing, let's examine the end result.
Words rotating in and out vertically. wow, very cool!
I've created a Codepen you can use and play with as well to see it in action in just a simple example
Rotating text in the browser, WWOOWW
HTML elements
The feature is made up of 2 HTML elements that slowly rotate in and out of visibility. First start with a parent div
with 2 children.
<div id='word-rotation'>
<div>A word</div>
<div></div>
</div>
At any time, only one of these div
blocks will be presented to the user. When a rotation happens, we want to gracefully transition the div
up and out of the screen by using transforms.
Javascript
This action requests Javascript and CSS to work together to create a nice animation. Let's start by reviewing the Javascript that I'm using.
// Create a counter that only increments up. Our words. And get the word rotation element
let index = 0;
const words = ["Javascript", "Python", "Rust", "GoLang", "Yaml"]
const rotationItem = document.getElementById('word-rotation')
// This example expects 2 children, make sure they exist
if (heroRotationItem.children[0] && heroRotationItem.children[1]) {
// If they do, loop and change text every 3 seconds
setInterval(() => {
const toHide = heroRotationItem.children[index % 2]
const toShow = heroRotationItem.children[(index + 1) % 2]
index += 1;
const nextItem = words[index % words.length]
toShow.textContent = nextItem;
toHide.classList.add('fadeOutUp')
toShow.classList.remove('fadeOutUp')
toHide.classList.remove('fadeInUp')
toShow.classList.add('fadeInUp')
}, 3000)
}
Everything until the setInterval
code is pretty straight forward. Create some counters, set some words to use and get the parent that has at least 2 child nodes. However, the core loop is a bit confusing but we can step through it.
We only want to be showing one element at a time, so of the 2 children, we set one toShow
and the other toHide
. Because we increment the counter every iteration of the loop, we can use the module (%
) operator to loop through them. We can also use module so that we always select an existing word from our list.
Once we have the child we want to show, we can set the text content of the node and add our css classes to it. The toHide
element can get the fadeOutUp
class while the toShow
element will get the fadeInUp
.
CSS classes
Let's take a closer look at these CSS classes
#word-rotation
class#word-rotation {
display: inline-grid;
position: relative;
}
#word-rotation > * {
grid-column: 1;
grid-row: 1;
text-align: left;
min-width: 250px;
animation-duration: 500ms;
animation-fill-mode: both;
-webkit-animation-duration: 500ms;
-webkit-animation-fill-mode: both;
transition: visibility 0s 500ms, opacity 500ms linear;
}
@keyframes fadeInUp {
from {
transform: translate3d(0,40px,0)
}
to {
transform: translate3d(0,0,0);
opacity: 1
}
}
@keyframes fadeOutUp {
from {
transform: translate3d(0,0,0)
}
to {
transform: translate3d(0,-40px,0);
opacity: 0;
width: 0px;
}
}
.fadeInUp {
opacity: 0;
animation-name: fadeInUp;
}
.fadeOutUp {
opacity: 1;
animation-name: fadeOutUp;
}
I think that everything here is pretty straight forward, except for 1 thing. How do we get the 2 elements to appear on top of each other? Well we can use display: inline-grid
for that and assign all children to the same cell using grid-column: 1; grid-row: 1
.
We then tie the fadeInUp
and fadeOutUp
classes to key frames that transition them between 0
opacity and 1
opacity. While this is going on, we translate them in 3D
space to new locations on the screen.
Conclusion
This demo showed how to create rotating words in the browser. I showed that it can be easily achieved with just a bit of HTML, CSS and Javascript. Someone else can extend this by creating an NPM
library and possibly polishing some of the rough edges that this implementation has (such as issues with screen resizing that I'll leave up to the reader to discover).