Mohd Akarm
Mohd Akarm

Reputation: 73

Wheel scroll issue: How to set scrolling so that only one section moves at a time?

I am coding for a scrollable website. It runs very well when I use a mouse, but I am facing an issue when using a laptop scroll pad. When I scroll using the laptop pad, these sections move twice as much, which is not good.

I want to each section to be visible only once during a single scroll.

Only code must be in vanilla javascript.

let sections = document.querySelectorAll(".section")
let sectionsWrap = document.getElementById("sections-wrap")

let currentSectionIndex = 0
let isScrolling = false

let scrollToSection = (index) => {
  sectionsWrap.style.transform = `translateY(-${index * 100}%)`
  sectionsWrap.style.transition = "transform 1s ease-in-out"
}

window.addEventListener("wheel", (event) => {
  if (isScrolling) return

  if (event.deltaY > 0 && currentSectionIndex < sections.length - 1) {
    currentSectionIndex++
  } else if (event.deltaY < 0 && currentSectionIndex > 0) {
    currentSectionIndex--
  } else {
    return
  }

  isScrolling = true
  scrollToSection(currentSectionIndex)

  setTimeout(() => {
    isScrolling = false
  }, 1200)
})
html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
}

#sections-wrap {
  width: 100%;
  height: 100%;
  height: 100%;
}

.section {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 2rem;
  color: white;
}

.section:nth-child(1) {
  background: #ff5733;
}

.section:nth-child(2) {
  background: #33ff57;
}

.section:nth-child(3) {
  background: #3357ff;
}

.section:nth-child(4) {
  background: #ff33a1;
}
<div id="sections-wrap">
  <div class="section">
    <h2>Fist Section</h2>
  </div>
  <div class="section">
    <h2>Second Section</h2>
  </div>
  <div class="section">
    <h2>Third Section</h2>
  </div>
  <div class="section">
    <h2>Fourth Section</h2>
  </div>
</div>

Upvotes: 2

Views: 39

Answers (1)

sam
sam

Reputation: 26

Your issue happens because touchpads send multiple scroll events quickly, making sections move too much.

I think it can be fixed by Adding a scroll threshold to detect intentional scrolls and prevent overscrolling like what I did here by changing the wheel event handler:

let sections = document.querySelectorAll(".section")
let sectionsWrap = document.getElementById("sections-wrap")

let currentSectionIndex = 0
let isScrolling = false

let scrollToSection = (index) => {
  sectionsWrap.style.transform = `translateY(-${index * 100}%)`
  sectionsWrap.style.transition = "transform 1s ease-in-out"
}

window.addEventListener("wheel", (event) => {
  if (isScrolling || Math.abs(event.deltaY) < 20) return; //leave scrolls

  if (event.deltaY > 0 && currentSectionIndex < sections.length - 1) {
    currentSectionIndex++;
  } else if (event.deltaY < 0 && currentSectionIndex > 0) {
    currentSectionIndex--;
  } else {
    return;
  }

  isScrolling = true;
  scrollToSection(currentSectionIndex);

  setTimeout(() => (isScrolling = false), 1200);
}, {
  passive: false
});
html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
}

#sections-wrap {
  width: 100%;
  height: 100%;
  height: 100%;
}

.section {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 2rem;
  color: white;
}

.section:nth-child(1) {
  background: #ff5733;
}

.section:nth-child(2) {
  background: #33ff57;
}

.section:nth-child(3) {
  background: #3357ff;
}

.section:nth-child(4) {
  background: #ff33a1;
}
<div id="sections-wrap">
  <div class="section">
    <h2>Fist Section</h2>
  </div>
  <div class="section">
    <h2>Second Section</h2>
  </div>
  <div class="section">
    <h2>Third Section</h2>
  </div>
  <div class="section">
    <h2>Fourth Section</h2>
  </div>
</div>

Upvotes: 1

Related Questions