Roko Simultaneous Scroll with Wheel and Scrollbar

by thomastthai

HTML

<div class="scrollSyncV" id="a">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit.
  Consequuntur rerum rem quae iste earum aspernatur.
  Laudantium eum, animi maiores unde itaque,
  repellat sed magni dicta earum alias, ipsa ad labore!
  Deserunt recusandae modi. Earum autem provident eum in officia.
  Lorem ipsum dolor sit amet, consectetur adipisicing elit.
  Iure possimus doloribus veritatis dolores voluptate quae
  fuga eaque mollitia magni nam exercitationem ratione itaque
  est debitis dolor, nemo repudiandae voluptas sequi!
<br>
End.
</div>
<div class="scrollSyncV" id="b">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit.
  Consequuntur rerum rem quae iste earum aspernatur.
  Laudantium eum, animi maiores unde itaque,
  repellat sed magni dicta earum alias, ipsa ad labore!
<br>End.
</div>

CSS

:root {
  padding: 1rem;
}

body {
  display: flex;
}

.scrollSyncV {
  width: 50%;
  height: 10rem;
  overflow: auto;
  outline: 1px solid black;
  box-sizing: border-box;
  font-size: 2.5rem;
}

.scrollSyncV div {
  border: 10px dashed #aaa;
}

JavaScript

const elsDIV = document.querySelectorAll(".scrollSyncV");

const manualScroll = (evt) => {
  const elThis = evt.target;
  const elOther = [...elsDIV].filter(e => e !== elThis)[0];
  const diff = elThis.scrollTop - elThis._scrollTopOld;
  elOther.scrollBy({top: diff});
  elThis._scrollTopOld += diff;
};

elsDIV.forEach(el => {

  el._scrollTopOld = el.scrollTop;
  const elOther = [...elsDIV].filter(e => e !== el)[0];

  el.addEventListener("scroll", (evt) => {
    evt.preventDefault();
  });

  el.addEventListener("pointerenter", () => {
    el.addEventListener("scroll", manualScroll);
    elOther.removeEventListener("scroll", manualScroll);
  });

  el.addEventListener("wheel", (evt) => {
    const delta = Math.sign(evt.deltaY);

    console.log(Math.round(el.scrollTop + el.clientHeight), el.scrollHeight)
    
    if( // smaller element cannot scroll any more - continue to scroll the taller one:
      delta === -1 && Math.round(el.scrollTop) === 0 ||
      delta ===  1 && Math.round(el.scrollTop + el.clientHeight) === el.scrollHeight
    ) {
        elOther.scrollBy({top: evt.deltaY, behavior: "smooth"});
    }

  });

});