How to prevent page scrolling when scrolling a DIV element?
Update 2: My solution is based on disabling the browser's native scrolling altogether (when cursor is inside the DIV) and then manually scrolling the DIV with JavaScript (by setting its .scrollTop
property). An alternative and IMO better approach would be to only selectively disable the browser's scrolling in order to prevent the page scroll, but not the DIV scroll. Check out Rudie's answer below which demonstrates this solution.
Here you go:
$( '.scrollable' ).on( 'mousewheel DOMMouseScroll', function ( e ) {
var e0 = e.originalEvent,
delta = e0.wheelDelta || -e0.detail;
this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30;
e.preventDefault();
});
Live demo: https://jsbin.com/howojuq/edit?js,output
So you manually set the scroll position and then just prevent the default behavior (which would be to scroll the DIV or whole web-page).
Update 1: As Chris noted in the comments below, in newer versions of jQuery, the delta information is nested within the .originalEvent
object, i.e. jQuery does not expose it in its custom Event object anymore and we have to retrieve it from the native Event object instead.
If you don't care about the compatibility with older IE versions (< 8), you could make a custom jQuery plugin and then call it on the overflowing element.
This solution has an advantage over the one Šime Vidas proposed, as it doesn't overwrite the scrolling behavior - it just blocks it when appropriate.
$.fn.isolatedScroll = function() {
this.bind('mousewheel DOMMouseScroll', function (e) {
var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.detail,
bottomOverflow = this.scrollTop + $(this).outerHeight() - this.scrollHeight >= 0,
topOverflow = this.scrollTop <= 0;
if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) {
e.preventDefault();
}
});
return this;
};
$('.scrollable').isolatedScroll();
I think it's possible to cancel the mousescroll event sometimes: http://jsfiddle.net/rudiedirkx/F8qSq/show/
$elem.on('wheel', function(e) {
var d = e.originalEvent.deltaY,
dir = d < 0 ? 'up' : 'down',
stop = (dir == 'up' && this.scrollTop == 0) ||
(dir == 'down' && this.scrollTop == this.scrollHeight-this.offsetHeight);
stop && e.preventDefault();
});
Inside the event handler, you'll need to know:
- scrolling direction
d = e.originalEvent.deltaY, dir = d < 0 ? 'up' : 'down'
because a positive number means scrolling down - scroll position
scrollTop
for top,scrollHeight - scrollTop - offsetHeight
for bottom
If you're
- scrolling up, and
top = 0
, or - scrolling down, and
bottom = 0
,
cancel the event: e.preventDefault()
(and maybe even e.stopPropagation()
).
I think it's better to not override the browser's scrolling behaviour. Only cancel it when applicable.
It's probablt not perfectly xbrowser, but it can't be very hard. Maybe Mac's dual scroll direction is tricky though...