home about me

<marquee>: Alternatives in CSS

Remember back in the late 90’s, early 00’s? Geocities, Angelfire, Tripod, no personal website was complete without the scrolling text provided by the <marquee> tag. Now that it is officially deprecated, let’s look at implementing an alternative.

Status Quo

Chances are this example might work for you:

<marquee>
  This text is wrapped in marquee tags.
</marquee>
This text is wrapped in marquee tags.

That does not mean you should use it. The marquee tags are so obsolete, even caniuse refuses to track any information on them. Oct 12, 2021: As of 2020, caniuse tracks marquee support, while still strongly recommending against their usage. Support could be dropped at any moment, and what’s worse, people will laugh at you if you use them.

Simple CSS3 Implementation

Let’s recreate some marquee’ish effects in CSS! The basics are easy enough, we start out with a wrapping container and a scrolling child element. For the sake of the example, I’m not using vendor prefixes.

.container {
  overflow: hidden;
  position: relative;
}

.container::before {
  content: '\00a0';
}

.scrolling {
  animation: marquee 10s linear infinite;
  display: block;
  min-width: 100%;
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
}

@keyframes marquee {
  from {
    transform: translateX(100%);
  }
  to { 
    transform: translateX(-100%);
  }
}
This scrolling text is implemented using CSS3.

The container element hides its overflow, so we don’t get horizontal scrollbars. It’s also got position: relative so we get a new positioning context. If you want to define the font size for your scroller, do it on the container.

The pseudo element for the container has \00a0 for content - that’s unicode for a non-breaking space. We need this because the scrolling child element will be absolutely positioned, causing the container to collapse otherwise.

The scrolling element itself is where the magic happens. white-space: nowrap makes sure our text stays in a single line. The absolute position is necessary so the element gets its full width, even if it’s wider than the parent container. Otherwise the animation, which is relative to the element size, would not go all the way through. Same goes for min-width: 100%.

The animation itself should be self-explanatory. The translate transformation’s percentage value is relative to the element’s width.

Repeating Text

This is where things get interesting. To create a seamless scrolling animation, we need to repeat the scrolling element often enough to fill the whole line container width, plus one entry. We’re inlining those elements, so make sure there’s no white space between them. The whitespace between our scrolling elements would throw off the transform calculation and lead to nasty jumping.

Please remember to set aria-hidden="true" on all repeat elements, so your users’ screen reader won’t sound like a broken record.

<div class="container">
  <div class="scrolling">
    Marquee rocks!
  </div><div class="scrolling" aria-hidden="true">
    Marquee rocks!
  </div><div class="scrolling" aria-hidden="true">
    Marquee rocks!
  </div><div class="scrolling" aria-hidden="true">
    Marquee rocks!
  </div>
  <!-- … -->
</div>

No surprises in the CSS code for this example. We don’t need the absolutely positioned scrolling element, but they need to be inlined and get a slight padding, to compensate for the lost whitespace between elements.

.container {
  overflow: hidden;
  white-space: nowrap;
}

.scrolling {
  animation: marquee 2s linear infinite;
  display: inline-block;
  padding-right: 10px;
}

@keyframes marquee {
  from {
    transform: translateX(0);
  }
  to { 
    transform: translateX(-100%);
  }
}
Marquee rocks!

The scrolling elements are not really going all the way through to the left. Instead, they move their width, until the first element is completely hidden, and then jump to their initial positions. See this colored example:

Marquee rocks!

Vertical Scrolling

Going for a vertical scroll effect is dead simple.

Lorem ipsum dolor sit amet, usu ne nemore facilisi elaboraret, vim ei modo alia constituam, mel novum prompta commune te. Per et alii nostrud vulputate, ne sit movet vocibus minimum.
.container {
  overflow: hidden;
}

.scrolling {
  animation: marquee 3s linear infinite;
}

@keyframes marquee {
  from {
    transform: translateY(100%);
  }
  to { 
    transform: translateY(-100%);
  }
}

Vertical Scrolling, Single Line

We can utilize the technique from the horizontal demo for a vertical scroller too:

Lorem ipsum dolor sit amet, usu ne nemore facilisi elaboraret, vim ei modo alia constituam, mel novum prompta commune te. Per et alii nostrud vulputate, ne sit movet vocibus minimum.
.container {
  overflow: hidden;
  position: relative;
}

.container::before {
  content: '\00a0';
}

.scrolling {
  animation: marquee 3s linear infinite;
  left: 0;
  position: absolute;
  top: 0;
}

@keyframes marquee {
  from {
    transform: translateY(100%);
  }
  to { 
    transform: translateY(-100%);
  }
}

Vertical Scrolling, Repeating

Just as with the horizontal repeating marquee, repeat elements are necessary. The container element also needs a fixed height, but whitespace can be ignored in this case.

Lorem ipsum dolor sit amet, usu ne nemore facilisi elaboraret, vim ei modo alia constituam, mel novum prompta commune te. Per et alii nostrud vulputate, ne sit movet vocibus minimum.
.container {
  height: 29px;
  overflow: hidden;
}

.scrolling {
  animation: marquee 3s linear infinite;
}

@keyframes marquee {
  from {
    transform: translateY(0);
  }
  to { 
    transform: translateY(-100%);
  }
}

Reversal

The effects can be reversed by either switching the order of the keyframe definitions, or simply setting animation-direction: reverse.

Marquee rocks!
Lorem ipsum dolor sit amet, usu ne nemore facilisi elaboraret, vim ei modo alia constituam, mel novum prompta commune te. Per et alii nostrud vulputate, ne sit movet vocibus minimum.

Final Thoughts

While stylistic use cases for marquees might exist, there are also some good reasons the tag is considered deprecated and was never an official part of the HTML specs. Don’t move text you actually want your users to read.

But playing around with it can still be fun:

See the Pen Studio Toto Chaos Slider by René Roth (@rrorg) on CodePen.