< Koba ! >

Infinite Custom Marquee

Last updated: April 23, 2025

Latest update: Bug fixes!

!! IMPORTANT !! If you are already using an older version of this resource (ie. You have used this resource earlier than April 25, 2025), there are some changes that might break your marquees! It is HIGHLY recommended that you copy all of the CSS and JavaScript from this resource again and overwrite your older version to ensure there are no issues. If you have made custom changes, you will need to re-add them afterwards. I apologize about the inconvenience!

Major thanks to my NekoWeb neighbor, Harriet!! She has been a major help with testing and finding the bugs fixed in this update. I also want to say thanks to one of her friends who also brought these issues to light. Please go check out her website and give her a follow!


Have a marquee on your site? Don't like the default behaviour that leaves that big nasty gap every scroll-cycle? Tired of these stupid questions?? This is the resource for you!

But okay, on a serious note; After combing through a lot of tutorials and resources online, I found that a lot of people don't account for having multiple unique items inside of a custom marquee. A lot of the examples I found only had a working "infinite" effect on a single string of text, and that was super annoying! So I finally figured out how to make my own marquee, that works with (theorhetically) an infinite amount of items inside of it!

So without futher waiting, let's jump right into it.

Part 1: HTML

The HTML is actually very simple! The marquee consists of 3 main parts:

  1. The main marquee element
  2. A "container" div which will hold all the items inside your marquee, and
  3. The marquee items (Buttons, stamps, text, etc.)

For this resource, I will simply be copying the marquee that you can find on my home page!


<div class="marquee">
  <div class="marquee-items">
    <a href="https://joosh.nekoweb.org/" target="_blank"><img src="https://koba.nekoweb.org/imgs/buttons/joosh.gif"></a>
    <a href="https://trademarkhell.net/"><img src="https://koba.nekoweb.org/imgs/buttons/tmsspecialhell.png"
        alt="trademarkization company of 2003"></a>
    <a href="https://dimden.dev/"><img src="https://koba.nekoweb.org/imgs/buttons/dimden.gif"></a>
    <a href="https://foxball.nekoweb.org" title="The Vulpe Zone"><img
        src="https://koba.nekoweb.org/imgs/buttons/foxball.png" alt="Foxball's Nekoweb" /></a>
    <a href="https://social.nekoweb.org/" title="Nekoweb Cafe"><img
        src="https://koba.nekoweb.org/imgs/buttons/nekowebcafe.gif" alt="Nekoweb Cafe"></a>
    <a href="https://max.nekoweb.org/"><img src="https://koba.nekoweb.org/imgs/buttons/max.gif"
        alt="max's apartment"></a>
  </div>
</div>
        

Part 2: CSS

Next up is the CSS. This is where most of the actual "magic" of the custom marquee happens. First, we have to set up a keyframes animation, and create a class that runs that animation.


@keyframes scroll-r2l {
  from {
    transform: translateX(0);
  }

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

.scroll-r2l {
  animation: scroll-r2l 10s linear infinite;
}
        

Notice how the animation is named with -r2l? Keep this in mind for later!

Next, we have to style all of the HTML elements we created! The most important part is the overflow and flex, but almost everything else can be customized to your preference!


.marquee {
  overflow: hidden;
  display: flex;
  flex-wrap: nowrap;
  box-sizing: unset;
  
  /*  You dont need a border or a set width on yours, but it makes the effect look better if the marquee width is smaller than the number of items in your marquee  */
  border: 3px solid black;
  width: 500px;
}

.marquee-items {
  display: flex;
  flex-shrink: 0;
  height: 100%; /* This line is extremely important to prevent bugs on some browsers such as FireFox */
  min-width: 100%;
  position: relative;
}

/* Changes to this class will only affect the children
of the marquee-items, and not all of their descendants.
Make changes here if you want spaces in-between the
marquee items or other effects and styles!*/
.marquee-items > * {
  margin: 0;
  height: 31px;
}
        

Part 3: JavaScript

Don't worry! The JavaScript is actually really simple. If you named your divs the same as I have (.marquee, .marquee-items) then you shouldn't have to modify this at all. One additional thing that is nice, is that this script will handle every single custom marquee on your page at the same time! Just copy and add this script to the bottom of your page, before the </body> tag.


<script>
function handleMarquee() {
// Get all marquees on page
const marquees = document.querySelectorAll(".marquee");

// Loop through each marquee
  marquees.forEach((marquee) => {
    // Get the main container and clone it
    // And then add the clone to the marquee
    const container = marquee.querySelector(".marquee-items");
    let clone = container.cloneNode(true);
    marquee.appendChild(clone);
    
    // Finally, add the scroll class at the same time so there is no gaps in the scrolling effect
    // We also determine if the items should be scrolling right-to-left instead by default, and adjust the marquees flex
    // direction and which animation the containers use if so
    if (marquee.dataset.direction == "right") {
      marquee.style.flexDirection = "row-reverse";
      container.classList.add("scroll-l2r");
      clone.classList.add("scroll-l2r");
    } else {
      container.classList.add("scroll-r2l");
      clone.classList.add("scroll-r2l");
    }
  });
}
handleMarquee();
</script>
        

Now hold on there! Some of you might be asking now, "Koba, what's that if-statement there talking about with dataset direction? You didn't show us that!"

Remember how I said to keep in mind how the CSS animation is named with -r2l? Thats where that comes in!

Part 4: Reversing the direction

So, if you don't want your marquee to scroll from left-to-right, then you can basically stop here. Otherwise, we just need to make some minor adjustments and/or additions to the HTML and CSS!

HTML

To tell our script that we want to scroll the items from left-to-right instead, we just need to add a custom data attribute to the main marquee element:


<div class="marquee" data-direction="right">
  ...
</div>
        

This custom data attribute is what is read during that if-statement in our script! If our script finds this data, and the data reads "right", then the script adjusts our custom marquee element to have a flex-direction of "row-reverse". This means that all of the containers within the marquee will be placed in reverse order.

CSS

Then, we just have to add in another keyframes animation and a class:


@keyframes scroll-l2r {
  from {
    transform: translateX(0);
  }

  to {
    transform: translateX(100%);
  }
}

.scroll-l2r {
  animation: scroll-l2r 10s linear infinite;
}
        

And with all of that, you should have a result that looks something like this!

trademarkization company of 2003 Foxball's Nekoweb Nekoweb Cafe max's apartment

trademarkization company of 2003 Foxball's Nekoweb Nekoweb Cafe max's apartment

(NEW) Part 5: Pausing the marquee

So, after all of that, there is still one core "feature" of marquee's that we are missing... The ability to pause it!

Thankfully, this is actually an extremely easy thing to do! I have also gone ahead and added the ability to make it so that only the marquee's you want to be paused on hover will be affected, instead of every marquee on the entire page... if that is a behaviour you desire.

So lets get into it!

HTML

You might not want every single marquee on your page to pause when hovered, so we will make use of another custom data attribute to tell our script what elements we want this new behaviour to affect:


<div class="marquee" data-pause="true">
  ...
</div>
        

This can also be used together with our other data attribute so you can have any of your reversed marquee's also paused!

CSS

Next up, adding a new class into our CSS:


.paused {
  -webkit-animation-play-state:paused;
  -moz-animation-play-state:paused;
  -o-animation-play-state:paused;
  animation-play-state:paused;
}
        

This new class is what tells our marquee to stop playing its current animation. All four of those lines do the exact same thing, they all just add browser compatibility.

JavaScript

Lastly, we need to add the following lines into our JavaScript. Here is the full script again; Pay attention to the comments! You can either replace your entire previous script, or otherwise you will only need to copy in the last part before the script ends!


<script>
function handleMarquee() {
  // Get all marquees on page
  const marquees = document.querySelectorAll(".marquee");
  
  // Loop through each marquee
  marquees.forEach((marquee) => {
    // Get the main container and clone it
    // And then add the clone to the marquee
    const container = marquee.querySelector(".marquee-items");
    let clone = container.cloneNode(true);
    marquee.appendChild(clone);
    // Finally, add the scroll class at the same time so there is no gaps in the scrolling effect
    // We also determine if the items should be scrolling right-to-left instead by default, and adjust the marquees flex direction and which animation the containers use if so
    if (marquee.dataset.direction == "right") {
      marquee.style.flexDirection = "row-reverse";
      container.classList.add("scroll-l2r");
      clone.classList.add("scroll-l2r");
    } else {
      container.classList.add("scroll-r2l");
      clone.classList.add("scroll-r2l");
    }
    
    // !! NEW STUFF FOR PAUSING; COPY BELOW
    
    // First we check for the new data attribute to see if pausing this marquee is allowed:
    if (marquee.dataset.pause == "true") {
      
      // If pausing is allowed, we simply add some mouse events for when the mouse
      // enters and leaves the marquee that add and remove our new 'paused' class to
      // the .marquee-items containers
      marquee.onmouseover = e => {
        container.classList.add("paused");
        clone.classList.add("paused");
      }
      marquee.onmouseout = e => {
        container.classList.remove("paused");
        clone.classList.remove("paused");
      }
    }
    
    // !! END NEW STUFF FOR PAUSING
  });
}
handleMarquee();
</script>
        

With those new changes, you should now have a marquee that can be paused when you hover over it! Notice how this marquee pauses, but none of the others on the page do?

trademarkization company of 2003 Foxball's Nekoweb Nekoweb Cafe max's apartment

If you want to see this without all of my blabbing, check out my CodePen where you can see and play around with this exact code to see what everything does!

Once again as well, big shout-outs to Harriet for helping me with all the bug fixes and testing!


<< Return to main blog

Hosted by  

Made by me! ©2024-