tony
tony

Reputation: 614

Can't horizontal scroll past 200vw

I have this code that goes from vertical to horizontal and back to vertical scrolling.

If I set the min-width to 50vw I can only see 4 sections, if I set it to 100vw (shown in example) it will only show 2 section.

There seems to be a width limit of 200vw, why can't I display anything over that?

I don't really understand why and thus I don't understand how to fix it. Here is my code:

let lastKnownScrollPosition = 0;
        let deltaY = 0;

        window.addEventListener("scroll", wheelHandler);
        
        document.querySelectorAll('.sticky-container').forEach(function(container) {
            const stikyContainerHeight = (container.querySelector('main').offsetWidth + window.innerHeight);
            container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');
        });
        

        function isElementInViewport(el) {
            const rect = el.getBoundingClientRect();
            return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
        }

        function wheelHandler(event) {

            deltaY = window.scrollY - lastKnownScrollPosition;
            lastKnownScrollPosition = window.scrollY;


            const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container) {
                return isElementInViewport(container);
            })[0];

            if (!containerInViewPort) {
                return;
            }

            var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop;
            var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop;
            let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;


            if (g_canScrollHorizontally) {              

                containerInViewPort.querySelector('main').scrollLeft +=  deltaY;

            }
        }
html,
    body {
        margin: 0;
        font-family: sans-serif;
    }

    .vertical-section {
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    main {
        overflow-x: hidden;
        display: flex;
        position: sticky;
        top: 0;
    }

    h1 {
        margin: 0;
        padding: 0;
    }

    section {
        min-width: 100vw; /*Works perfeclty when it's 50vw*/
        min-height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 4ch;
    }

    section:nth-child(even) {
        background-color: teal;
        color: white;
    }
<div class="vertical-section">
        Content Before
    </div>
    <div class="sticky-container">
        <main>
            <section>
                <h1>First</h1>
            </section>
            <section>
                <h1>Second</h1>
            </section>
            <section>
                <h1>Third</h1>
            </section>
      <section>
                <h1>Fourth</h1>
            </section>
      <section>
                <h1>Fifth</h1>
            </section>
            <section>
                <h1>Last</h1>
            </section>
        </main>
    </div>
    <div class="vertical-section">
        Content After
    </div>

Can someone tell me what's going on here and how to fix it?

Upvotes: 0

Views: 92

Answers (1)

dale landry
dale landry

Reputation: 8610

Basically when you scroll on the Y axis => up/down, the amount it will scroll from left to right, or on the X axis, is relevant to the height of the distance you are calculating in your forEach loop stikyContainerHeight.

For example, If your container is 500px wide using the 100vw css rule, and you have 6 elements total with 5 being past the right fold, this would basically be (500px * 6 = 3000px). When you scroll down in height, in order to get the width needed to show all 3000px, you must make your height the same in pixels. You can iterate over the elements that make up the main sections children and add those widths together or you can take the width of the screen and multiply it by the length of the parents sections children.

You are only adding enough distance in scrollable height to allow it to scroll two divs on the X axis. If you want it to scroll the entire distance, then get the width of the entire parent element and then multiply that by the amount of sections you are scrolling and apply to the stikyContainerHeight variable.

let lastKnownScrollPosition = 0;
let deltaY = 0;

// changed to a single query
const main = document.querySelector('.sticky-container'); 

// get the section elements so we can use its nodelist arrays length
const sec = document.querySelectorAll('.sticky-container section'); 

window.addEventListener("scroll", wheelHandler);

// no need for the forEach loop as there is only one element witht he class sticky-container
const stikyContainerHeight = main.getBoundingClientRect().width * sec.length;
main.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');

// everything below here is the same
function isElementInViewport(el) {
  const rect = el.getBoundingClientRect();
  return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
}

function wheelHandler(event) {

  deltaY = window.scrollY - lastKnownScrollPosition;
  lastKnownScrollPosition = window.scrollY;


  const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container) {
    return isElementInViewport(container);
  })[0];

  if (!containerInViewPort) {
    return;
  }

  var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop;
  var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop;
  let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;


  if (g_canScrollHorizontally) {

    containerInViewPort.querySelector('main').scrollLeft += deltaY;

  }
}
html,
body {
  margin: 0;
  font-family: sans-serif;
}

.vertical-section {
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

main {
  overflow-x: hidden;
  display: flex;
  position: sticky;
  top: 0;
}

h1 {
  margin: 0;
  padding: 0;
}

section {
  min-width: 100vw;
  /*Works perfeclty when it's 50vw*/
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 4ch;
}

section:nth-child(even) {
  background-color: teal;
  color: white;
}
<div class="vertical-section">
  Content Before
</div>
<div class="sticky-container">
  <main>
    <section>
      <h1>First</h1>
    </section>
    <section>
      <h1>Second</h1>
    </section>
    <section>
      <h1>Third</h1>
    </section>
    <section>
      <h1>Fourth</h1>
    </section>
    <section>
      <h1>Fifth</h1>
    </section>
    <section>
      <h1>Last</h1>
    </section>
  </main>
</div>
<div class="vertical-section">
  Content After
</div>

You could also iterate over the sections themselves and concatenate their values in a forEach loop.

let stikyContainerHeight = Number();

sec.forEach(s => stikyContainerHeight += s.getBoundingClientRect().width);

main.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');

Upvotes: 2

Related Questions