JavaScript jQuery JS Plugins Methods

Cross-Browser Mousewheel Event Handler

Capturing mousewheel scroll events in JavaScript is more awkward than it should be. Each browser exposes a different event name and a different property for the scroll direction and magnitude — and to make things worse, the sign convention is inverted between Firefox and everyone else. Here is a complete breakdown of the differences and a unified wrapper function.

The Browser Differences

  • Firefox fires DOMMouseScroll. The delta is read from event.detail. A positive value means scrolling down; negative means up.
  • IE, Chrome, Safari fire mousewheel. The delta is read from event.wheelDelta. A positive value means scrolling up; negative means down — the opposite sign from Firefox.
  • IE (legacy) does not support addEventListener and requires attachEvent instead, with the event object retrieved from window.event.

A Unified Cross-Browser Solution

The function below normalises all three cases into a single callback that receives the original event and a delta value where 1 always means scroll up and -1 always means scroll down:

function addMouseWheelEvent(el, fn) {
    if (el.addEventListener) {
        // Firefox
        el.addEventListener('DOMMouseScroll', function(e) {
            fn.call(el, e, e.detail > 0 ? -1 : 1);
        }, false);
        // Chrome, Safari, IE9+
        el.addEventListener('mousewheel', function(e) {
            fn.call(el, e, e.wheelDelta > 0 ? 1 : -1);
        }, false);
    } else {
        // IE6, IE7, IE8
        el.attachEvent('onmousewheel', function(e) {
            e = window.event;
            fn.call(el, e, e.wheelDelta > 0 ? 1 : -1);
        });
    }
}

// Usage
addMouseWheelEvent(document.getElementById('scroll-area'), function(e, delta) {
    // delta: 1 = scroll up, -1 = scroll down
    this.scrollTop -= delta * 30;
    e.preventDefault ? e.preventDefault() : (e.returnValue = false);
});

Preventing Default Scroll Behaviour

When you handle the mousewheel event on a custom scrollable element, you almost always want to prevent the browser from also scrolling the page. The last line of the callback handles this cross-browser: e.preventDefault() works in standards-compliant browsers; setting e.returnValue = false is the IE equivalent.

jQuery Plugin Version

If you are already using jQuery, the jQuery Mousewheel plugin by Brandon Aaron handles all of the above automatically. It is the standard cross-browser solution in the jQuery ecosystem and provides a consistent event.deltaY value (positive = up, negative = down) on a normalised mousewheel event across all browsers.

Plugin repository: https://github.com/jquery/jquery-mousewheel

// With the jQuery Mousewheel plugin loaded:
$('#scroll-area').on('mousewheel', function(e) {
    this.scrollTop -= e.deltaY * 30;
    e.preventDefault();
});

A Note on Delta Magnitude

Both the raw wheelDelta and detail values carry magnitude information (how far the wheel was turned in one event), but the values are not comparable between browsers and vary by OS and hardware. For most UI purposes it is simplest to ignore magnitude and treat every wheel event as a single step, as the examples above do.