How to create infinite text scrolling in HTML, CSS, and JavaScript

It’s worth noting that a horizontal marquee brings many accessibility challenges. Moving text can be distracting and difficult to read. Consider carefully the kind of content you wish to display in this way!

Basics: How the text scroll effect works

This text scroll effect can be achieved using simple CSS animation properties. To make text scroll horizontally on a webpage, we’ll add sample text in a container element and apply the transform:translateX() CSS property to the text as shown below ↓

The text is moved using transform:translateX() property inside a @keyframes animation. The animation starts with the text at 0% (initial position) and moves to -100%  (text moves out of view to the left).

The scroll animation is applied using:

1
animation: scrollText 25s linear infinite;

where:

  • scrollText is the name of the animation
  • 25s is the duration of the animation
  • linear makes the scrolll speed consistent
  • inifinite means the animation will repeat forever

To scroll text vertically, we use transform:translateY property inside a @keyframe animation. In the next example, we have duplicated the text and made the container taller to accommodate the scrolling text.

How to create an infinite horizontal and vertical text scroll effect

Let’s combine all the tricks we have learned so far and create a stylish infinite vertical and horizontal text scroll effect.

HTML structure

In our HTML structure, we have separate containers for each scroll direction. The horizontal scroll will occupy the main content area while the vertical scroll will be in a sidebar. By the end of this tutorial, we will have something like this:

The HTML structure will look like this:

1
 <div class="main-container">
2
      <div class="scroll-container">
3
        <div class="text-row">
4
          <div class="infinite-scroll">
5
            <div class="text-scroll">
6
              <!-- text added here -->
7
            </div>
8

9
            <div class="text-scroll">
10
              <!-- text added here -->
11
            </div>
12
          </div>
13
        </div>
14
      </div>
15

16
      <div class="vertical-scroll-container">
17
        <div class="vertical-infinite-scroll">
18
          <div class="vertical-text-scroll">
19
            <!-- text added here -->
20
          </div>
21
          <div class="vertical-text-scroll">
22
            <!-- text added here -->
23
          </div>
24
        </div>
25
      </div>
26
    </div>

The scrolling text will be added dynamically using JavaScript. For each scroll direction, we will duplicate each pair of scrolling text elements to create a seamless looping animation.

Main CSS styles

Firstly, let’s remove the default spacing on the body, so set overflowX: hidden to prevent horizontal scrolling. We’ll also apply a custom font.

1
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@800&display=swap");
2
body {
3
font-family: "Montserrat", sans-serif;
4
margin: 0;
5
padding: 0;
6
overflow-x: hidden;
7
display: flex;
8
min-height: 100vh;
9
color: #000;
10
background-color: #adea74;
11
}

We have also applied a bright Envato green background to provide contrast with the “soft serve” of the scrolling text containers.

Align the sections side by side using flexbox and set the main container to full width.

1
.main-container {
2
 display: flex;
3
 width: 100%;
4
}

The horizontal scroll container will take the full width of the webpage, while the vertical scroll container will have a width of 200px.

1
.scroll-container {
2
  flex-grow: 1;
3
  overflow: hidden;
4
}
5

6
.vertical-scroll-container {
7
  width: 200px;
8
  background-color: #fef5ee;
9
  border-left: 2px solid rgba(0, 0, 0, 0.1);
10
  overflow: hidden;
11
}

Add scroll text to the webpage with JavaScript

Before we start animating, let’s inject the text to be animated to the Dom with JavaScript. This could be done manually too, but adding text dynamically like this gives us more flexibility. 

Get  the horizontal and vertical text scroll elements, in our case, these two elements.

1
const horizontalTextScroll = document.querySelectorAll(".text-scroll");
2
const verticalTextScroll = document.querySelectorAll(
3
".vertical-text-scroll"
4
);

Define a list of phrases that will appear in our scroll animation.

1
const items = [
2
    "Digital Strategy",
3
    "Design System",
4
    "Brand Strategy",
5
    "Website Design",
6
    "SEO Optimization",
7
    "Content Strategy",
8
  ];

We will then loop through each phrase in the items array and pass it as an argument to the addScrollItem function. This function is responsible for adding the text and star to both the horizontal and vertical scrolling containers on the webpage.

1
items.forEach((item) => {
2
    addItemToScrolls(item);
3
  });

To create an infinite horizontal scrolling effect, we loop through each element defined by horizontalTextScroll  and since there are two of them, we insert the same set of text items into both.

The duplication is important to ensure that when one set scrolls out of view, the next scrolls in ensuring a seamless loop.

The function look like this:

1
function addItemToScrolls(text) {
2
  
3
  horizontalTextScroll.forEach((scrollItem) => {
4
    const textItem = document.createElement("span");
5
    textItem.classList.add("text-item");
6
    textItem.innerHTML = text;
7
    scrollItem.appendChild(textItem);
8

9
  });
10
}

In the same loop, we will also add a star (★) between each phrase to enhance the visual experience. Update the code as shown below.

1
function addItemToScrolls(text) {
2

3
  horizontalTextScroll.forEach((scrollItem) => {
4
    const textItem = document.createElement("span");
5
    textItem.classList.add("text-item");
6
    textItem.innerHTML = text;
7
    scrollItem.appendChild(textItem);
8

9
    const star = createStar();
10
    star.classList.add("star");
11
    scrollItem.appendChild(star);
12
  });
13
}
14

15
function createStar() {
16
    const star = document.createElement("span");
17
    star.textContent = "";
18
    return star;
19
  }

To create an infinite vertical scrolling effect, follow the same steps as the horizontal scroll except rather than adding the full phrase, for example, “Digital Stategy”, we only take the first word, in this case, “Digital” and add it to the scroll element.

We will also perform duplication to ensure a continuous loop.   

1
function addItemToScrolls(text) {
2
    
3
  horizontalTextScroll.forEach((scrollItem) => {
4
    const textItem = document.createElement("span");
5
    textItem.classList.add("text-item");
6
    textItem.innerHTML = text;
7
    scrollItem.appendChild(textItem);
8

9
    const star = createStar();
10
    star.classList.add("star");
11
    scrollItem.appendChild(star);
12
  });
13

14
  verticalTextScroll.forEach((scrollItem) => {
15
    const textItem = document.createElement("span");
16
    textItem.classList.add("vertical-text-item");
17
    const firstWord = text.split(" ")[0];
18
    textItem.textContent = firstWord;
19
    scrollItem.appendChild(textItem);
20

21
    const star = createStar();
22
    scrollItem.appendChild(star);
23
  });
24
}

Animating the text with CSS

We’ll start with the horizontal section. Define the animations using CSS @keyframes.

1
@keyframes scroll {
2
    0% {
3
      transform: translateX(0);
4
    }
5
    100% {
6
      transform: translateX(-50%);
7
    }
8
  }

The element will have no movement at 0% (its original position), and by the end of the animation, the text will have moved by 50% of its width. This means the text will slide halfway off the left side of its parent container.

Since we are duplicating the content inside the same container, we use translateX(-50%) so that when the first half moves out of view, the second half takes its place, creating a seamless scrolling loop.

To ensure the animation repeats infinitely and runs at a constant speed, set the animation to 25s linear infinite . 

1
.infinite-scroll {
2
    animation: scroll 25s linear infinite;
3
    
4
  }

Set display:flex to ensure the duplicated text elements are displayed in a row. 

1
.infinite-scroll {
2
    display: flex;
3
    animation: scroll 25s linear infinite;
4
    
5
  }

To draw attention to the content as it moves across the webpage, increase the font size of the text and the star and add a bigger font weight to the text. 

1
.text-item {
2
  font-size: 2rem;
3
  font-weight: 800;
4
}
5

6
.star {
7
  font-size: 2rem;
8
  margin: 10px 30px;
9
}

Vertical scrolling animation

To create the vertical scrolling effect, we will follow the same animation steps, but this time, instead of moving the content sideways using translateX, we will use translateY to move the content vertically. We’re also presented with some interesting challenges with the way the text is laid out—we’ll solve those with Flexbox and another unusual CSS property.

Define another keyframe animation similar to the previous one for the vertical infinite scroll.  

1
@keyframes scrollVertical {
2
    0% {
3
      transform: translateY(0);
4
    }
5
    100% {
6
      transform: translateY(-50%);
7
    }
8
  }

Add the animation to the vertical scroll container.

1
.vertical-infinite-scroll {
2
  display: flex;
3
  flex-direction: column;
4
  animation: scrollVertical 25s linear infinite;
5
}

The text on the vertical scroll needs to be flipped to ensure the characters are arranged from top to bottom. In CSS, we use the writing-mode property which allows us to define the direction in which text is laid out.

1
.vertical-text-item {
2
    writing-mode: vertical-rl;
3
   
4
  } 

After setting the writing mode, we also need to flip the text so it appears upright from top to bottom using the transform: rotate(360) property. 

1
.vertical-text-item {
2
    writing-mode: vertical-rl;
3
    transform: rotate(180deg);
4
   
5
  } 

Now we have this effect on the vertical scroll.

Apply flex:display to ensure the two pairs of text are arranged in a column and set flex-direction: column to stack them vertically. Additionally, set flex-shrink: 0; to stop  the items from shrinking when there is insufficient space.

1
.vertical-text-scroll {
2
    display: flex;
3
    flex-direction: column;
4
    align-items: center;
5
    flex-shrink: 0;
6
  }

Final scrolling text demo

Here is a reminder of the final scroll demo.

If you are looking for more advanced effects, check out our tutorial on How to Build Horizontal Marquee Effects with GSAP, and take your animations to the next level with GSAP.

Conclusion

In this tutorial, we have used simple CSS properties to achieve horizontal and vertical text scroll effects. These effects can easily be integrated into any design, making it an eye-catching addition to any webpage.