htmlcssmarquee

Marquee doesn't scroll everything


I have a client of mine that's using a marquee, I know, I know it's a depreciated tag and frankly shouldn't be used. This is a personal website of his, and he's been a client of mine for a while, so I figured I'd implement the marquee but do so in a modern way without using depreciated tags. I have seen lots of different solutions for this. I generally use flexbox for something like this because it doesn't rely on javascript or jQuery, but flexbox marquee examples often rely on a hard-coded width to calculate the speed of keyframe animations.

So, long story short, I am seeking to create a marquee that's responsive, but the speed doesn't change based on how much content it's scrolling (I know it's alot to ask). My client also writes a ton of content (I've tried to convince him otherwise, but he still does it).

I put something together that's very close to being a solution. It doesn't use flexbox, but it does resize well without changing the speed...I'm getting pretty close to what I'm after. At the end of the day I don't have to use flexbox, so if all the other boxes are checked I'm good with that!

This is the code I'm using:

<div class="pizza">
    <p class="duck"><span class="red">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span> <span class="green">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span> <span class="blue">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>.</p>
</div>

The CSS:

.green {
    color: green;
}

.red {
    color: red;
}

.blue {
    color: blue;
}

.pizza {
    line-height: 60px;
    font-size: 16px;
    overflow: hidden;
    position: relative;
    white-space: nowrap;
}

p.duck {
  animation: scroll-left 20s linear infinite;
}

@keyframes scroll-left {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(-100%, 0);
  }
}

p.duck:hover {
    animation-play-state: paused;
}

Fiddle: https://jsfiddle.net/L7kbhyg6/

I added some spans so the problem is easier to see, but basically not all of the text is scrolling. I see red, then green, then the marquee jumps and it starts over again. Not sure how to get it to display all of my content.

Thanks,
Josh


Solution

  • I think in this case using JS requestAnimationFrame would be the best way. – Mister Jojo

    Could you create an example, I'm not sure how to implement this solution.

    well here it is..
    [ Edit : changed to take care on screen resizing masking]
    [ Edit : first version with unique ID => code for only one "marquee" per page]

    (()=>  // IIFE closure  for <marquee> simulation on #pizza element
      {
      const
        pizza   = document.querySelector('#pizza')
      , pizza_p = document.querySelector('#pizza > p')
      , mov     = { pos   : pizza.offsetWidth
                  , max   : -pizza_p.offsetWidth
                  , pause : false 
                  };
      pizza.addEventListener('mouseenter', ()=>
        { 
        mov.pause = true; 
        });
      pizza.addEventListener('mouseleave', ()=>
        { 
        mov.pause = false; 
        requestAnimationFrame(MarqueeMov); 
        });
     
      // auto launch
      pizza_p.style.left = `${mov.pos}px`;
      requestAnimationFrame(MarqueeMov);
      
      function MarqueeMov()
        {
        pizza_p.style.left = `${--mov.pos}px`;
    
        if ( mov.pos < mov.max 
          || mov.pos > pizza.offsetWidth // added to take care of screen resize
          )
          mov.pos = pizza.offsetWidth;
    
        if (!mov.pause)
          requestAnimationFrame(MarqueeMov);
        }
      }
    )();
    .green { color: green; }
    .red   { color: red;   }
    .blue  { color: blue;  }
    
    #pizza {
      position    : relative;
      font-size   : 16px;
      height      : 32px;
      padding     : 0;
      overflow    : hidden;
      white-space : nowrap;
      cursor      : pointer;
      }
    #pizza > p {
      margin   : 0;
      position : absolute;
      bottom   : 0;
      left     : 0;
      }
    <div id="pizza">
      <p>
        <span class="red">
          Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
        </span> 
        <span class="green">
          Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
        </span>
        <span class="blue">
          Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
        </span>
      </p>
    </div>

    Second version, allowing you to manage several "horizontal marquee" fields on the same page

    (()=>  // IIFE closure  for <marquee> simulation for <div class="JS-Marquee"> elements
      {
      const
        jsMarquees = [...document.querySelectorAll('.JS-Marquee')].map( jsMx =>
          { 
          let txtP = jsMx.querySelector('p');
          return ({ boxElm  : jsMx
                  , boxLen  : jsMx.offsetWidth
                  , txtElm  : txtP 
                  , txtPEnd : -txtP.offsetWidth
                  , txtPos  : jsMx.offsetWidth
                  , pause   : false 
                  });
          });
      jsMarquees.actives = jsMarquees.length;
    
      window.addEventListener('resize', ()=>
        {
        jsMarquees.forEach( jsM => { jsM.boxLen = jsM.boxElm.offsetWidth });
        });
    
      jsMarquees.forEach( jsM =>
        {
        jsM.boxElm.addEventListener('mouseenter',()=>
          {
          jsM.pause = true;
          --jsMarquees.actives;
          });
        jsM.boxElm.addEventListener('mouseleave',()=>
          {
          jsM.pause = false;
          ++jsMarquees.actives;
          if (jsMarquees.actives===1)
            requestAnimationFrame(MarqueeMoves); 
          });
        })
    
      // auto launch
      jsMarquees.forEach( jsM => { jsM.txtElm.style.left = `${jsM.txtPos}px`; })
      requestAnimationFrame(MarqueeMoves);
    
      function MarqueeMoves()
        {
        jsMarquees.forEach( jsM =>
          {
          if (jsM.pause) return;
    
          --jsM.txtPos;
    
          if ( jsM.txtPos > jsM.boxLen
            || jsM.txtPos < jsM.txtPEnd 
            ) 
            jsM.txtPos = jsM.boxLen;
    
          jsM.txtElm.style.left = `${jsM.txtPos}px`;
          });
    
        if (jsMarquees.actives)
          requestAnimationFrame(MarqueeMoves); 
        }
    
    })();  // IIFE end of <marquee> JS simulation
    .green { color: green; }
    .red   { color: red;   }
    .blue  { color: blue;  }
    
    .JS-Marquee {
      position    : relative;
      font-size   : 16px;
      height      : 32px;
      padding     : 0;
      overflow    : hidden;
      white-space : nowrap;
      cursor      : pointer;
      }
    .JS-Marquee > p {
      margin   : 0;
      position : absolute;
      bottom   : 0;
      left     : 0;
      }
    <div class="JS-Marquee">
      <p>
        <span class="red">
          Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
        </span> 
        <span class="green">
          Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
        </span>
        <span class="blue">
          Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
        </span>
      </p>
    </div>
    
    <div class="JS-Marquee">
      <p>
        <span class="green">
          Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
        </span> 
        <span class="blue">
          Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
        </span>
      </p>
    </div>