Marquee · Simple

Endlessly moving text simply built with HTML and CSS.

Beginner
Component
HTML
CSS
View Demo
Marquee · Simple thumbnail

What is Marquee?

Marquee is a popular, eye-catching component used on many awwward winning websites. It allows for vertical or horizontal scrolling text. It’s even seen in real-life in examples like train stations, or other group events providing up-to-date and potentionally lengthy information.

In early web dev days, it was very popular and even had a native and widely supported HTML element: <marquee>. While the <marquee> element is no longer supported, marquee is still extremely popular and adds a now more artistic feel and interesting visual interest. There’s many ways to build it, and you can get as intense as you’d like. The level of intensity depends on what features are required.

Choosing the Right Technology

If you need a simple version that doesn’t have any user interaction, HTML and CSS will do the trick. I’ll start with this simple example to demonstrate my thoughts behind the animation. Afterwards, there will be additional tutorials were we’ll rebuild it in a more modern context (using React and Framer). And then finally, I’ll add more advanced features such as adjusting the speed while hovering.

Building the HTML

To start, let’s setup the HTML. We begin with a div as our Container. You can think of this as what is visible to the user. Within that, we have the Track. The Track is what contains our “conveyer belt” of content (more on this in the next section). Here’s an illustration to demonstrate.

Simple Version HTML Demo

Transforming our illustration into HTML, we get:

<div class="container">
  <div class="track">
    Marquee Example
  </div>
</div>

The Animation’s Concept

Previously, I referred to the Track as a “conveyer belt”. What I didn’t show you was the full illustration, where our Track far extends beyond what the user is able to see. It extends beyond our viewport so that we have a constant stream of content that’s available to enter into view i.e. the “conveyer belt”. And once, we animate the track 50% to the left, we restart the animation— giving us a perfect loop of “endless content”. In order to hide this extra content flowing off the screen and to not cause horizontal overflow, we use overflow: hidden on our Container. In reality, this is what our HTML looks like:

Simple Version HTML Demo

Constraint: Must Have a Center Point

One important constraint is that our content has to have a perfect center point where each side of the center point has identical content. This is important so that when we restart the animation at 50% completion, the restart isn’t noticeable. If the center point is unbalanced in any way, the restart will cause the content to appear jumpy. In this illustration you can see the first half doesn’t match the second, so this would make the content appear jumpy.

Simple Version HTML Demo

A way we can guaruntee a center point, is by doubling the content a few times. If you double it at least once, it’s guarunteed to have a center point. Ensuring a center pointer (and that’s there’s enough content on the screen) we double the track’s content a few times.

Also, make sure to add an extra space at the end to match the space at the end of the first half using &nbsp; (See HTML below).

Simple Version HTML Demo

<div class="container">
  <div class="track">
    Marquee Example Marquee Example Marquee Example Marquee Example Marquee Example Marquee Example Marquee Example Marquee Example&nbsp;
  </div>
</div>

Setting up the Base CSS

Now that our HTML is ready, let’s set up our base CSS and validate the animation. For this, I’ll explain each portion as comments in the code.

  .container {
    background: black;

    /* Since our track is overflowing, we need to hide this to not cause horizontal scrolling. */
    overflow: hidden;
  }

  .track {
    font-size: 100px;
    color: white;

    /* We don't want this content to wrap. We want it to overflow off the screen. */
    width: max-content;

    /* This is used so that our &nbsp; actually takes up space. */
    white-space: pre;

    /*
      Try adding this transform and then commenting it out. You should see that your
      HTML exactly matches with it and without it. That means everything is setup
      correctly and your animation won't be jumpy.
    */
    transform: translateX(-50%);
  }

Setting up the Animation

Now that the base CSS is setup and we tested the transform will happen seemlessly. Now we can finally add the finally animation that makes the magic happen! 🎉

 @keyframes marquee {
    from {
      transform: translateX(0%);
    }

    to {
      transform: translateX(-50%);
    }
  }

  .container {
    background: black;
    overflow: hidden;
  }

  .track {
    font-size: 100px;
    color: white;
    width: max-content;
    white-space: pre;
    animation: marquee 5s linear infinite;
  }

Optional Challenge

Congrats on finishing this tutorial! If you want to try some extra challenges, these are fun and shouldn’t take long!

  1. Reverse the direction so that it comes from the other side.
  2. Refactor the animation and styling so the text is scrolling vertically instead of horizontally.
  3. Extend the vertical variation to also support reverse!

Feel free to look at the demo page to see what you should expect. It includes the challenge variations as well.

View Demo

Next Up: Building it with React and Framer.

Depending on your project or client, you may need to add interaction to the marquee. Some examples of this could be slowing it down (or entirely stopping it) on hover for better accessibility. Or maybe you want to allow the user to be able to drag it themselves? To help better set us up for these requirements, we’ll rebuild this simple example in React and use a library called Framer that helps manage animations.