153

Is there a way to get the mouse wheel events (not talking about scroll events) in jQuery?

Sergio
  • 28,539
  • 11
  • 85
  • 132
thejh
  • 44,854
  • 16
  • 96
  • 107
  • 2
    A quick search turned up [this plugin](http://brandonaaron.net/code/mousewheel/docs) that may help. – Jerad Rose Nov 18 '11 at 22:20
  • This solution works for me : http://stackoverflow.com/questions/7154967/jquery-detect-scrolldown – Bertie Mar 06 '14 at 12:07
  • @thejh posted a new answer on this with DOM3 events: http://stackoverflow.com/a/24707712/2256325 – Sergio Jul 14 '14 at 13:00
  • Possible duplicate of [jQuery scroll() detect when user stops scrolling](http://stackoverflow.com/questions/9144560/jquery-scroll-detect-when-user-stops-scrolling) – divy3993 Feb 02 '17 at 03:33
  • Just a note on this. If you're just wanting to detect changes to an input, and it's not detecting changes via the mouse wheel, try `$(el).on('input', ...` – rybo111 Jun 24 '18 at 09:54

15 Answers15

222
​$(document).ready(function(){
    $('#foo').bind('mousewheel', function(e){
        if(e.originalEvent.wheelDelta /120 > 0) {
            console.log('scrolling up !');
        }
        else{
            console.log('scrolling down !');
        }
    });
});
Ivan
  • 34,531
  • 8
  • 55
  • 100
mahdi shahbazi
  • 2,253
  • 2
  • 12
  • 2
  • 53
    The `DOMMouseScroll` event is used in FF, so you have to to listen on both `.bind('DOMMouseScroll mousewheel') {` evetns https://developer.mozilla.org/en-US/docs/DOM/DOM_event_reference/DOMMouseScroll – e382df99a7950919789725ceeec126 Apr 07 '13 at 10:26
  • 10
    `e.originalEvent.wheelDelta` is undefined in FF23 – hofnarwillie Sep 10 '13 at 10:44
  • 27
    You don't need to divide by 120 it is useless waste of cpu – venimus Sep 30 '13 at 11:21
  • 6
    must have been best answer –  Oct 13 '13 at 15:43
  • 2
    But anyway, why would you want to divide it by 120? What's that constant? (You don't have to, as venimus pointed out.) – Laszlo T Oct 04 '15 at 20:44
  • Thank you, mahdi shahbazi! It helped me so much. – Bondsmith Feb 27 '17 at 17:13
  • 1
    I would recommend the use of the 2nd argument of event handler function - `delta`: `$('#el').on('mousewheel', function(e, delta) { if(delta > 0) { /*up*/ } else { /*down*/ }})`. See [this answer](http://stackoverflow.com/a/43468489/1245149). – Mojo Apr 18 '17 at 09:39
  • `console.log(event.originalEvent.wheelDeltaY > 0 ? "Wheel Up " : "Wheel Down ");` – Elshan Jun 29 '17 at 15:51
  • @Mojo when I used `delta` it's gives `undefined` with Chrome Version 59.0.3071.115 (Official Build) (64-bit) – Elshan Jun 29 '17 at 15:56
  • The `mousewheel` event is non-standard and also deprecated. Use `WheelEvent` instead. – GetFree Mar 15 '18 at 04:27
  • This does work but the problem is if you scroll through touchpad, it creates a lot of scrolls, i.e. for a scroll with touch pad with high speed, multiple screens are scrolled. To solve all such issues, this plugin helped a lot: https://github.com/Promo/wheel-indicator – Yesha Apr 11 '19 at 07:41
153

Binding to both mousewheel and DOMMouseScroll ended up working really well for me:

$(window).bind('mousewheel DOMMouseScroll', function(event){
    if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
        // scroll up
    }
    else {
        // scroll down
    }
});

This method is working in IE9+, Chrome 33, and Firefox 27.


Edit - Mar 2016

I decided to revisit this issue since it's been a while. The MDN page for the scroll event has a great way of retrieving the scroll position that makes use of requestAnimationFrame, which is highly preferable to my previous detection method. I modified their code to provide better compatibility in addition to scroll direction and position:

(function() {
  var supportOffset = window.pageYOffset !== undefined,
    lastKnownPos = 0,
    ticking = false,
    scrollDir,
    currYPos;

  function doSomething(scrollPos, scrollDir) {
    // Your code goes here...
    console.log('scroll pos: ' + scrollPos + ' | scroll dir: ' + scrollDir);
  }

  window.addEventListener('wheel', function(e) {
    currYPos = supportOffset ? window.pageYOffset : document.body.scrollTop;
    scrollDir = lastKnownPos > currYPos ? 'up' : 'down';
    lastKnownPos = currYPos;

    if (!ticking) {
      window.requestAnimationFrame(function() {
        doSomething(lastKnownPos, scrollDir);
        ticking = false;
      });
    }
    ticking = true;
  });
})();
See the Pen Vanilla JS Scroll Tracking by Jesse Dupuy (@blindside85) on CodePen.

This code is currently working in Chrome v50, Firefox v44, Safari v9, and IE9+

References:

notgiorgi
  • 1,691
  • 12
  • 27
Jesse Dupuy
  • 1,728
  • 1
  • 11
  • 14
  • This worked the best for me. However, this script runs per "click" of the scroll wheel. This can be overwhelming for some scripts to use. Is there a way to treat each scroll event as one instance, instead of run the script per scroll wheel click? – invot May 28 '14 at 17:15
  • Not especially. From what I've seen, many people will either avoid dealing with scroll tracking, or they'll use a timer instead (e.g. check the user's position on the page every x milliseconds, etc). If there's a more performant solution out there, I definitely want to know about it! – Jesse Dupuy Aug 07 '14 at 23:48
  • 1
    I found a way to do this: http://stackoverflow.com/questions/23919035/using-jquery-to-detect-a-mouse-scroll-per-instance-not-per-click – invot Aug 07 '14 at 23:58
  • @JesseDupuy if a timer is to be used, make sure you *(or who ever is reading this)* is using a queue system for your different "threads". When stacking timers, it has horrible effect on your rendering. I built a script for this case that I'm sharing on github: https://github.com/erik-landvall/animator – superhero Aug 19 '15 at 15:19
  • Updated my answer with modern info + Codepen link :) – Jesse Dupuy Mar 07 '16 at 20:28
  • How we can cancel twice mousewheel ? – ShibinRagh Mar 23 '16 at 07:23
  • Are you saying the event is now firing double using my old/new code? Trying to make sure I understand the question. – Jesse Dupuy Mar 23 '16 at 17:22
  • 1
    Thanks for the update. Can you copy your code into your answer? Never know if codepen might go down someday. [It's happened before.](https://github.com/jsperf/jsperf.com/issues/18#issuecomment-113569132) – JDB Apr 23 '16 at 15:15
  • 2
    @JesseDupuy, I would upvote this answer, but your updated version doesn`t work if the document fits the view ("width: 100vh; height: 100vh") or got "overflow: hidden;". "window.addEventListener('scroll', callback)" is not the correct answer to "window.addEventListener('mousewheel', callback)". – Daniel May 06 '16 at 09:52
  • Great answer. As @Daniel pointed out, "overflow: hidden" doesn't work with the new version, but the original one works great with it. I needed it for web app that uses mouse scrolling to zoom, and it's working perfectly. – kevinmicke Feb 16 '17 at 19:39
71

As of now in 2017, you can just write

$(window).on('wheel', function(event){

  // deltaY obviously records vertical scroll, deltaX and deltaZ exist too.
  // this condition makes sure it's vertical scrolling that happened
  if(event.originalEvent.deltaY !== 0){

    if(event.originalEvent.deltaY < 0){
      // wheeled up
    }
    else {
      // wheeled down
    }
  }
});

Works with current Firefox 51, Chrome 56, IE9+

Louis Ameline
  • 2,779
  • 1
  • 25
  • 25
49

There's a plugin that detects up/down mouse wheel and velocity over a region.

JasCav
  • 34,458
  • 20
  • 113
  • 170
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
40

Answers talking about "mousewheel" event are refering to a deprecated event. The standard event is simply "wheel". See https://developer.mozilla.org/en-US/docs/Web/Reference/Events/wheel

Brian Di Palma
  • 7,043
  • 3
  • 19
  • 15
  • 20
    I tried these and found: "wheel" works in Firefox and IE but not Chrome. "mousewheel" works in Chrome and IE but not Firefox. "DOMMouseScroll" works only in Firefox. – Curtis Yallop Aug 22 '13 at 20:39
  • 1
    Whoa, this saved me a lot of time. Thanks! – gustavohenke Nov 20 '13 at 17:17
  • 5
    Looks like Chrome added support for "wheel" in August of 2013: https://code.google.com/p/chromium/issues/detail?id=227454 – rstackhouse Jul 07 '14 at 14:11
  • 2
    Safari still doesn't support the wheel event. – Thayne Sep 11 '14 at 16:11
  • As your documentation says, `wheel` event is supported on `Edge` not `IE` which is not the same thing. [CanIuse](https://www.caniuse.com/#search=wheel) – Alex Mar 06 '18 at 07:16
16

This worked for me:)

 //Firefox
 $('#elem').bind('DOMMouseScroll', function(e){
     if(e.originalEvent.detail > 0) {
         //scroll down
         console.log('Down');
     }else {
         //scroll up
         console.log('Up');
     }

     //prevent page fom scrolling
     return false;
 });

 //IE, Opera, Safari
 $('#elem').bind('mousewheel', function(e){
     if(e.originalEvent.wheelDelta < 0) {
         //scroll down
         console.log('Down');
     }else {
         //scroll up
         console.log('Up');
     }

     //prevent page fom scrolling
     return false;
 });

from stackoverflow

Community
  • 1
  • 1
Anjith K P
  • 2,158
  • 27
  • 35
14

Here is a vanilla solution. Can be used in jQuery if the event passed to the function is event.originalEvent which jQuery makes available as property of the jQuery event. Or if inside the callback function under we add before first line: event = event.originalEvent;.

This code normalizes the wheel speed/amount and is positive for what would be a forward scroll in a typical mouse, and negative in a backward mouse wheel movement.

Demo: http://jsfiddle.net/BXhzD/

var wheel = document.getElementById('wheel');

function report(ammout) {
    wheel.innerHTML = 'wheel ammout: ' + ammout;
}

function callback(event) {
    var normalized;
    if (event.wheelDelta) {
        normalized = (event.wheelDelta % 120 - 0) == -0 ? event.wheelDelta / 120 : event.wheelDelta / 12;
    } else {
        var rawAmmount = event.deltaY ? event.deltaY : event.detail;
        normalized = -(rawAmmount % 3 ? rawAmmount * 10 : rawAmmount / 3);
    }
    report(normalized);
}

var event = 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll';
window.addEventListener(event, callback);

There is also a plugin for jQuery, which is more verbose in the code and some extra sugar: https://github.com/brandonaaron/jquery-mousewheel

Community
  • 1
  • 1
Sergio
  • 28,539
  • 11
  • 85
  • 132
8

This is working in each IE, Firefox and Chrome's latest versions.

$(document).ready(function(){
        $('#whole').bind('DOMMouseScroll mousewheel', function(e){
            if(e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0) {
                alert("up");
            }
            else{
                alert("down");
            }
        });
    });
futuredayv
  • 81
  • 1
  • 4
5

I was stuck in this issue today and found this code is working fine for me

$('#content').on('mousewheel', function(event) {
    //console.log(event.deltaX, event.deltaY, event.deltaFactor);
    if(event.deltaY > 0) {
      console.log('scroll up');
    } else {
      console.log('scroll down');
    }
});
Seth
  • 10,198
  • 10
  • 45
  • 68
Prafull Sharma
  • 181
  • 4
  • 7
4

use this code

 knob.bind('mousewheel', function(e){  
 if(e.originalEvent.wheelDelta < 0) {
    moveKnob('down');
  } else {
    moveKnob('up');
 }
  return false;
});
1

The plugin that @DarinDimitrov posted, jquery-mousewheel, is broken with jQuery 3+. It would be more advisable to use jquery-wheel which works with jQuery 3+.

If you don't want to go the jQuery route, MDN highly cautions using the mousewheel event as it's nonstandard and unsupported in many places. It instead says that you should use the wheel event as you get much more specificity over exactly what the values you're getting mean. It's supported by most major browsers.

Cobertos
  • 1,953
  • 24
  • 43
0

my combination looks like this. it fades out and fades in on each scroll down/up. otherwise you have to scroll up to the header, for fading the header in.

var header = $("#header");
$('#content-container').bind('mousewheel', function(e){
    if(e.originalEvent.wheelDelta > 0) {
        if (header.data('faded')) {
            header.data('faded', 0).stop(true).fadeTo(800, 1);
        }
    }
    else{
        if (!header.data('faded')) header.data('faded', 1).stop(true).fadeTo(800, 0);
    }
});

the above one is not optimized for touch/mobile, I think this one does it better for all mobile:

var iScrollPos = 0;
var header = $("#header");
$('#content-container').scroll(function () {

    var iCurScrollPos = $(this).scrollTop();
    if (iCurScrollPos > iScrollPos) {
        if (!header.data('faded')) header.data('faded', 1).stop(true).fadeTo(800, 0);

    } else {
        //Scrolling Up
        if (header.data('faded')) {
            header.data('faded', 0).stop(true).fadeTo(800, 1);
        }
    }
    iScrollPos = iCurScrollPos;

});
0

If using mentioned jquery mousewheel plugin, then what about to use the 2nd argument of event handler function - delta:

$('#my-element').on('mousewheel', function(event, delta) {
    if(delta > 0) {
    console.log('scroll up');
    } 
    else {
    console.log('scroll down');
    }
});
Mojo
  • 187
  • 3
  • 14
0

I think many key things are a bit all over the place and I needed to read all the answers to make my code work as I wanted, so I will post my findings in just one place:

  • You should use "wheel" event over the other deprecated or browser specific events.
  • Many people here is getting something wrong: the opposite of x>0 is x<=0 and the opposite of x<0 is x>=0, many of the answers in here will trigger scrolling down or up incorrectly when x=0 (horizontal scrolling).
  • Someone was asking how to put sensitivity on it, for this you can use setTimeout() with like 50 ms of delay that changes some helper flag isWaiting=false and you protect yourself with if(isWaiting) then don't do anything. When it fires you manually change isWaiting=true and just below this line you start the setTimeout again who will later change isWaiting=false after 50 ms.
ajax333221
  • 11,436
  • 16
  • 61
  • 95
-3

I got same problem recently where $(window).mousewheel was returning undefined

What I did was $(window).on('mousewheel', function() {});

Further to process it I am using:

function (event) {
    var direction = null,
        key;

    if (event.type === 'mousewheel') {
        if (yourFunctionForGetMouseWheelDirection(event) > 0) {
            direction = 'up';
        } else {
            direction = 'down';
        }
    }
}
Szymon Toda
  • 4,454
  • 11
  • 43
  • 62