How can I determine the direction of a jQuery scroll event?

I'm looking for something to this effect:

$(window).scroll(function(event){
   if (/* magic code*/ ){
       // upscroll code
   } else {
      // downscroll code
   }
});

Any ideas?


Solution 1:

Check current scrollTop vs previous scrollTop

var lastScrollTop = 0;
$(window).scroll(function(event){
   var st = $(this).scrollTop();
   if (st > lastScrollTop){
       // downscroll code
   } else {
      // upscroll code
   }
   lastScrollTop = st;
});

Solution 2:

You can do it without having to keep track of the previous scroll top, as all the other examples require:

$(window).bind('mousewheel', function(event) {
    if (event.originalEvent.wheelDelta >= 0) {
        console.log('Scroll up');
    }
    else {
        console.log('Scroll down');
    }
});

I am not an expert on this so feel free to research it further, but it appears that when you use $(element).scroll, the event being listened for is a 'scroll' event.

But if you specifically listen for a mousewheel event by using bind, the originalEvent attribute of the event parameter to your callback contains different information. Part of that information is wheelDelta. If it's positive, you moved the mousewheel up. If it's negative, you moved the mousewheel down.

My guess is that mousewheel events will fire when the mouse wheel turns, even if the page does not scroll; a case in which 'scroll' events probably are not fired. If you want, you can call event.preventDefault() at the bottom of your callback to prevent the page from scrolling, and so that you can use the mousewheel event for something other than a page scroll, like some type of zoom functionality.

Solution 3:

Store the previous scroll location, then see if the new one is greater than or less than that.

Here's a way to avoid any global variables (fiddle available here):

(function () {
    var previousScroll = 0;

    $(window).scroll(function(){
       var currentScroll = $(this).scrollTop();
       if (currentScroll > previousScroll){
           alert('down');
       } else {
          alert('up');
       }
       previousScroll = currentScroll;
    });
}()); //run this anonymous function immediately

Solution 4:

Existing Solution

There could be 3 solution from this posting and other answer.

Solution 1

    var lastScrollTop = 0;
    $(window).on('scroll', function() {
        st = $(this).scrollTop();
        if(st < lastScrollTop) {
            console.log('up 1');
        }
        else {
            console.log('down 1');
        }
        lastScrollTop = st;
    });

Solution 2

    $('body').on('DOMMouseScroll', function(e){
        if(e.originalEvent.detail < 0) {
            console.log('up 2');
        }
        else {
            console.log('down 2');
        }
    });

Solution 3

    $('body').on('mousewheel', function(e){
        if(e.originalEvent.wheelDelta > 0) {
            console.log('up 3');
        }
        else {
            console.log('down 3');
        }
    });

Multi Browser Test

I couldn't tested it on Safari

chrome 42 (Win 7)

  • Solution 1
    • Up : 1 event per 1 scroll
    • Down : 1 event per 1 scroll
  • Solution 2
    • Up : Not working
    • Down : Not working
  • Solution 3
    • Up : 1 event per 1 scroll
    • Down : 1 event per 1 scroll

Firefox 37 (Win 7)

  • Solution 1
    • Up : 20 events per 1 scroll
    • Down : 20 events per 1 scroll
  • Solution 2
    • Up : Not working
    • Down : 1 event per 1 scroll
  • Solution 3
    • Up : Not working
    • Down : Not working

IE 11 (Win 8)

  • Solution 1
    • Up : 10 events per 1 scroll (side effect : down scroll occured at last)
    • Down : 10 events per 1 scroll
  • Solution 2
    • Up : Not working
    • Down : Not working
  • Solution 3
    • Up : Not working
    • Down : 1 event per 1 scroll

IE 10 (Win 7)

  • Solution 1
    • Up : 1 event per 1 scroll
    • Down : 1 event per 1 scroll
  • Solution 2
    • Up : Not working
    • Down : Not working
  • Solution 3
    • Up : 1 event per 1 scroll
    • Down : 1 event per 1 scroll

IE 9 (Win 7)

  • Solution 1
    • Up : 1 event per 1 scroll
    • Down : 1 event per 1 scroll
  • Solution 2
    • Up : Not working
    • Down : Not working
  • Solution 3
    • Up : 1 event per 1 scroll
    • Down : 1 event per 1 scroll

IE 8 (Win 7)

  • Solution 1
    • Up : 2 events per 1 scroll (side effect : down scroll occured at last)
    • Down : 2~4 events per 1 scroll
  • Solution 2
    • Up : Not working
    • Down : Not working
  • Solution 3
    • Up : 1 event per 1 scroll
    • Down : 1 event per 1 scroll

Combined Solution

I checked that side effect from IE 11 and IE 8 is come from if else statement. So, I replaced it with if else if statement as following.

From the multi browser test, I decided to use Solution 3 for common browsers and Solution 1 for firefox and IE 11.

I referred this answer to detect IE 11.

    // Detect IE version
    var iev=0;
    var ieold = (/MSIE (\d+\.\d+);/.test(navigator.userAgent));
    var trident = !!navigator.userAgent.match(/Trident\/7.0/);
    var rv=navigator.userAgent.indexOf("rv:11.0");

    if (ieold) iev=new Number(RegExp.$1);
    if (navigator.appVersion.indexOf("MSIE 10") != -1) iev=10;
    if (trident&&rv!=-1) iev=11;

    // Firefox or IE 11
    if(typeof InstallTrigger !== 'undefined' || iev == 11) {
        var lastScrollTop = 0;
        $(window).on('scroll', function() {
            st = $(this).scrollTop();
            if(st < lastScrollTop) {
                console.log('Up');
            }
            else if(st > lastScrollTop) {
                console.log('Down');
            }
            lastScrollTop = st;
        });
    }
    // Other browsers
    else {
        $('body').on('mousewheel', function(e){
            if(e.originalEvent.wheelDelta > 0) {
                console.log('Up');
            }
            else if(e.originalEvent.wheelDelta < 0) {
                console.log('Down');
            }
        });
    }