Search code examples
jquerybrowserscrollrendermarquee

Sliding div horizontally while scrolling vertically - Browser rendering


I have a functioning example of the sliding effect (below), but it seems to render oddly in the browser. Sometimes the letters look like they are split. Sometimes it looks like parts of them are stuck, while other parts are moving.

I'm currently using Firefox v111. I've also tried Chrome and Safari, but the issue appears intermittently on all of them. Is it the browsers or perhaps the code?

Jquery

$(window).on('scroll',function(){
        var elemPosition = Math.round($(window).scrollTop() / $(window).height() * 600);
    $('.marquee-l').css('margin-left', elemPosition);
    $('.marquee-r').css('margin-right', elemPosition);
});

Html

<div class="marquee-wrapper">
<div class="marquee-l">
This text is pushed from the left
</div>
</div>

<div class="marquee-wrapper">
<div class="marquee-r">
And this line is pushed from the right
</div>
</div>

Solution

  • The issue you're seeing is most likely caused by sub-pixel rendering. When elements are positioned with decimal values, some browsers will cause the issue.

    By using transform: translateX() instead of margin-left and margin-right, you may get smoother animation, and by using a web font and adjusting the text-rendering property.

    Try below snippet once

    $(window).on('scroll',function(){
        var elemPosition = Math.round($(window).scrollTop() / $(window).height() * 600);
        $('.marquee-l').css('transform', 'translateX(' + Math.round(elemPosition) + 'px)');
        $('.marquee-r').css('transform', 'translateX(-' + Math.round(elemPosition) + 'px)');
    });
    body {
      height: 800px;
      background-color: white;
    }
    .blank {
      height: 100px;
    }
    .marquee-wrapper {
        width: 100%;
        height: 50px;
        overflow: hidden;
        display: flex;
        flex-wrap: nowrap;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        background-color: #170c36;
    }
    .marquee-l, .marquee-r {
        height: 50px;
        line-height: 50px;
        text-align: center;
        white-space: nowrap;
        font-size: 20pt;
        transition: all 3s ease-out;
        -webkit-text-fill-color: transparent;
        -webkit-text-stroke: 1px #6f58ad;
    
        text-rendering: optimizeLegibility; /* Improves font rendering */
        white-space: nowrap; /* Prevents text from wrapping */
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="blank"></div>
    <div class="marquee-wrapper">
      <div class="marquee-l">
        This text is pushed from the left This text is pushed from the left This
        text is pushed from the left This text is pushed from the left This text is
        pushed from the left
      </div>
    </div>
    <div class="marquee-wrapper">
      <div class="marquee-r">
        And this line is pushed from the right And this line is pushed from the
        right And this line is pushed from the right And this line is pushed from
        the right
      </div>
    </div>

    If still not getting done, try to check below thing.

    const slideLeft = document.querySelector(".marquee-wrapper .marquee-l");
    const slideRight = document.querySelector(".marquee-wrapper .marquee-r");
    
    window.addEventListener("scroll", () => {
      const scrollPosition = Math.round(window.scrollY);
      slideLeft.style.marginLeft = `${-scrollPosition}px`;
      slideRight.style.marginRight = `${-scrollPosition}px`;
    });
    body {
      height: 800px;
      background-color: white;
    }
    
    .blank {
      height: 100px;
    }
    .marquee-wrapper {
      width: 100%;
      height: 50px;
      overflow: hidden;
      display: flex;
      flex-wrap: nowrap;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background-color: #170c36;
    }
    
    .marquee-l,
    .marquee-r {
      height: 50px;
      line-height: 50px;
      text-align: center;
      white-space: nowrap;
      font-size: 20pt;
      transition: all 0.9s ease-out;
      -webkit-text-fill-color: transparent;
      -webkit-text-stroke: 1px #6f58ad;
    }
    <div class="blank"></div><div class="blank"></div>
    
    <div class="marquee-wrapper">
      <div class="marquee-l">
        This text is pushed from the left This text is pushed from the left This
        text is pushed from the left This text is pushed from the left This text is
        pushed from the left
      </div>
    </div>
    <div class="marquee-wrapper">
      <div class="marquee-r">
        And this line is pushed from the right And this line is pushed from the
        right And this line is pushed from the right And this line is pushed from
        the right
      </div>
    </div>