4

I'm displaying an element on scrolling down and hiding it when scrolling up again. Without using setTimeout, this works just as expected. However, using setTimeout causes the 'display' class to be added and removed in short intervals when scrolling down. How can I avoid this while keeping the delay?

onscroll = function() {
  var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  if (scrollTop > 110) {
    menuButton.classList.add('display');
  } else {
    setTimeout(function() {
      menuButton.classList.remove('display');
    }, 400);
  }
}
Georg
  • 463
  • 1
  • 5
  • 15

2 Answers2

2

You have to check the scroll position after the setTimeout executes the function. It can be different after the timeout.

EDIT: If you don't want to the timeout to be triggered more than once you can clear it with clearTimeout.

var timerId;
onscroll = function() {
  var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  if (scrollTop > 110) {
    menuButton.classList.add('display');
    clearTimeout(timerId);
  } else {
    timerId = setTimeout(function() {
      if (!(scrollTop > 110)) {
          menuButton.classList.remove('display');
      }
    }, 400);
  }
}
undefined
  • 2,051
  • 3
  • 26
  • 47
  • That doesn't fix it. It seems like the else statement is executed twice just after scrolling even though the scrollTop is >110. – Georg Aug 08 '14 at 18:47
  • The `onscroll` event may trigger more than once, before `setTimeout` is triggered. – undefined Aug 08 '14 at 18:49
  • That must be it. After changing the interval from 400 to 0 it works just fine. How do I keep the interval then? – Georg Aug 08 '14 at 18:52
  • 1
    Okay, I figured it out. The timeout was still firing from earlier scroll events (since it's delayed). Cancelling the timeout did the trick. – Georg Aug 08 '14 at 18:58
2

The timeout was still firing from earlier events. Here is my fix:

onscroll = function() {
  var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  var timer;
  if (scrollTop > 110) {
    window.clearTimeout(timer);
    menuButton.classList.add('display');
  } else {
    timer = window.setTimeout(function() {
          menuButton.classList.remove('display');
      }, 400);
  }
}
Georg
  • 463
  • 1
  • 5
  • 15