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

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?

Solutions/Answers:

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
  • Soltion 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
  • Soltion 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
  • Soltion 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
  • Soltion 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
  • Soltion 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
  • Soltion 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');
            }
        });
    }

Solution 5:

I understand there has already been an accepted answer, but wanted to post what I am using in case it can help anyone. I get the direction like cliphex with the mousewheel event but with support for Firefox. It’s useful doing it this way in case you are doing something like locking scroll and can’t get the current scroll top.

See a live version here.

$(window).on('mousewheel DOMMouseScroll', function (e) {

    var direction = (function () {

        var delta = (e.type === 'DOMMouseScroll' ?
                     e.originalEvent.detail * -40 :
                     e.originalEvent.wheelDelta);

        return delta > 0 ? 0 : 1;
    }());

    if(direction === 1) {
       // scroll down
    }
    if(direction === 0) {
       // scroll up
    }
});

Solution 6:

Scroll Event

The scroll event behaves oddly in FF (it is fired a lot of times because of the smoothness scrolling) but it works.

Note: The scroll event actually is fired when dragging the scroll bar, using cursor keys or mousewheel.

//creates an element to print the scroll position
$("<p id='test'>").appendTo("body").css({
    padding: "5px 7px",
    background: "#e9e9e9",
    position: "fixed",
    bottom: "15px",
    left: "35px"
});

//binds the "scroll" event
$(window).scroll(function (e) {
    var target = e.currentTarget,
        self = $(target),
        scrollTop = window.pageYOffset || target.scrollTop,
        lastScrollTop = self.data("lastScrollTop") || 0,
        scrollHeight = target.scrollHeight || document.body.scrollHeight,
        scrollText = "";

    if (scrollTop > lastScrollTop) {
        scrollText = "<b>scroll down</b>";
    } else {
        scrollText = "<b>scroll up</b>";
    }

    $("#test").html(scrollText +
      "<br>innerHeight: " + self.innerHeight() +
      "<br>scrollHeight: " + scrollHeight +
      "<br>scrollTop: " + scrollTop +
      "<br>lastScrollTop: " + lastScrollTop);

    if (scrollHeight - scrollTop === self.innerHeight()) {
      console.log("► End of scroll");
    }

    //saves the current scrollTop
    self.data("lastScrollTop", scrollTop);
});

Wheel Event

You also may take a look at MDN, it exposes a great information about the Wheel Event.

Note: The wheel event is fired only when using the mousewheel; cursor keys and dragging the scroll bar does not fire the event.

I read the document and the example: Listening to this event across browser
and after some tests with FF, IE, chrome, safari, I ended up with this snippet:

//creates an element to print the scroll position
$("<p id='test'>").appendTo("body").css({
    padding: "5px 7px",
    background: "#e9e9e9",
    position: "fixed",
    bottom: "15px",
    left: "15px"
});

//attach the "wheel" event if it is supported, otherwise "mousewheel" event is used
$("html").on(("onwheel" in document.createElement("div") ? "wheel" : "mousewheel"), function (e) {
    var evt = e.originalEvent || e;

    //this is what really matters
    var deltaY = evt.deltaY || (-1 / 40 * evt.wheelDelta), //wheel || mousewheel
        scrollTop = $(this).scrollTop() || $("body").scrollTop(), //fix safari
        scrollText = "";

    if (deltaY > 0) {
        scrollText = "<b>scroll down</b>";
    } else {
        scrollText = "<b>scroll up</b>";
    }

    //console.log("Event: ", evt);
    $("#test").html(scrollText +
      "<br>clientHeight: " + this.clientHeight +
      "<br>scrollHeight: " + this.scrollHeight +
      "<br>scrollTop: " + scrollTop +
      "<br>deltaY: " + deltaY);
});