0

I'm creating a secondary view that will pop-up on clicking on a link. Content within this secondary view is vertically scrollable and horizontally fixed. The issue is: when scroll reach to the top/bottom of the secondary view, the background page will scroll as well, also if attempt to scroll left/right, the background page will also scroll.

I did some search online but mostly suggest to modify the body css. Due to project constraint, we are not allowed to modify any attribute on body. So I'm trying to find a solution without making css change.

I was trying to achieve using this approach:

        secondaryView.addEventListener('wheel', (event) => {
            if (//mouse scroll up and secondaryView is at top
                || //mouse scroll down and secondaryView is at bottom
                || //mouse scroll left or right) {
                event.preventDefault();
            }
        });

However, the problem is I don't know how to detect whether mouse scroll is horizontal, not able to rely on event.deltaX since it will be non-zero sometimes when scrolling up or down as well.

Oleg Valter
  • 6,098
  • 6
  • 22
  • 37
yunjing li
  • 57
  • 7

1 Answers1

0

This problem has a lot of solutions (see this huge Q&A for options), one of which is listening for scroll event instead of the wheel one (after all, you do not want to be limited to mouse wheel, do you?).

The easiest version (given that for some reason you cannot modify styling) is to keep track of the last known scroll position of the primary view (or the window) and as soon as the secondary view is shown (a boolean flag should suffice), start snapping the primary to it with scrollTo.

The rest depends on your exact requirements - if you need the primary to be scrollable while the secondary is open, things become complex (a solution for mouse-based devices may be to track cursor position to determine what is scrolled).

(() => {

  const p = document.getElementById("primary");
  const s = document.getElementById("secondary");
  const b = document.getElementById("show");

  let secondaryShown = false;

  b.addEventListener("click", () => {
    if (secondaryShown) {
      s.classList.remove("shown");
      secondaryShown = false;
      return;
    }

    s.classList.add("shown");
    secondaryShown = true;
  });

  let lknownYPos = window.scrollY,
    lknownXPos = window.scrollX;

  window.addEventListener("scroll", ({
    target,
    currentTarget
  }) => {

    if (secondaryShown) {
      window.scrollTo(lknownXPos, lknownYPos)
    }

    lknownWindowPos = window.scrollY;
  }, true);

})();
body {
  margin: 0;
}

.subcontent {
  height: 300vh;
  width: 300vw;
}

#primary {
  width: 200vw;
  height: 200vh;
}

#secondary {
  overflow-x: scroll;
  width: 50vw;
  height: 50vh;
  background-color: rgba(0, 0, 0, 0.25);
  z-index: 9999;
  color: white;
  display: none;
  font-size: 2rem;
  text-align: center;
}

.shown {
  display: block !important;
}
<div class="content">

<div id="primary">

  <button id="show">Switch secondary</button>

  <div id="secondary">
    <p>Secondary</p>
    <div class="subcontent"></div>
  </div>

</div>

</div>
Oleg Valter
  • 6,098
  • 6
  • 22
  • 37