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 fromevent.detail. A positive value means scrolling down; negative means up. - IE, Chrome, Safari fire
mousewheel. The delta is read fromevent.wheelDelta. A positive value means scrolling up; negative means down — the opposite sign from Firefox. - IE (legacy) does not support
addEventListenerand requiresattachEventinstead, with the event object retrieved fromwindow.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.