Scrolling child div scrolls the window, how do I stop that?

JavascriptHtml

Javascript Problem Overview


I have a div, with a scroll bar, When it reaches the end, my page starts scrolling. Is there anyway I can stop this behavior ?

Javascript Solutions


Solution 1 - Javascript

You can inactivate the scrolling of the whole page by doing something like this:

<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>

Solution 2 - Javascript

Found the solution.

http://jsbin.com/itajok

This is what I needed.

And this is the code.

http://jsbin.com/itajok/edit#javascript,html

Uses a jQuery Plug-in.


Update due to deprecation notice

From jquery-mousewheel:

> The old behavior of adding three arguments (delta, deltaX, and deltaY) > to the event handler is now deprecated and will be removed in later > releases.

Then, event.deltaY must now be used:

var toolbox = $('#toolbox'),
    height = toolbox.height(),
    scrollHeight = toolbox.get(0).scrollHeight;

toolbox.off("mousewheel").on("mousewheel", function (event) {
  var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
  return !blockScrolling;
});

Demo

Solution 3 - Javascript

The selected solution is a work of art. Thought it was worthy of a plugin....

$.fn.scrollGuard = function() {
    return this
        .on( 'wheel', function ( e ) {
            var event = e.originalEvent;
            var d = event.wheelDelta || -event.detail;
            this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
            e.preventDefault();
        });
};    

This has been an ongoing inconvenience for me and this solution is so clean compared to other hacks I've seen. Curious to know how more about how it works and how widely supported it would be, but cheers to Jeevan and whoever originally came up with this. BTW - stackoverflow answer editor needs this!

UPDATE

I believe this is better in that it doesn't try to manipulate the DOM at all, only prevents bubbling conditionally...

$.fn.scrollGuard2 = function() {
  return this
    .on( 'wheel', function ( e ) {
      var $this = $(this);
      if (e.originalEvent.deltaY < 0) {
        /* scrolling up */
        return ($this.scrollTop() > 0);
      } else {
        /* scrolling down */
        return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
      }
    })
  ;
};    

Works great in chrome and much simpler than other solutions... let me know how it fares elsewhere...

FIDDLE

Solution 4 - Javascript

You could use a mouseover event on the div to disable the body scrollbar and then a mouseout event to activate it again?

E.g. The HTML

<div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
    content
</div>

And then the javascript like so:

var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
    body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
    body.style.overflowY = 'auto';
}

Solution 5 - Javascript

Here's a cross-browser way to do this on the Y axis, it works on desktop and mobile. Tested on OSX and iOS.

var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var deltaY = event.deltaY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
}, {passive:false});

scrollArea.addEventListener("touchstart", function(event) {
    this.previousClientY = event.touches[0].clientY;
}, {passive:false});

scrollArea.addEventListener("touchmove", function(event) {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var currentClientY = event.touches[0].clientY;
    var deltaY = this.previousClientY - currentClientY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
    this.previousClientY = currentClientY;
}, {passive:false});

Solution 6 - Javascript

As answered here, most modern browsers now support the overscroll-behavior: none; CSS property, that prevents scroll chaining. And that's it, just one line!

Solution 7 - Javascript

I wrote resolving for this issue

  var div;
  div = document.getElementsByClassName('selector')[0];

  div.addEventListener('mousewheel', function(e) {
    if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
      e.preventDefault();
      div.scrollTop = div.scrollHeight;
    } else if (div.scrollTop + e.deltaY <= 0) {
      e.preventDefault();
      div.scrollTop = 0;
    }
  }, false);

Solution 8 - Javascript

If I understand your question correctly, then you want to prevent scrolling of the main content when the mouse is over a div (let's say a sidebar). For that, the sidebar may not be a child of the scrolling container of the main content (which was the browser window), to prevent the scroll event from bubbling up to its parent.

This possibly requires some markup changes in the following manner:

<div id="wrapper"> 
    <div id="content"> 
    </div> 
</div> 
<div id="sidebar"> 
</div> 

See it's working in this sample fiddle and compare that with this sample fiddle which has a slightly different mouse leave behavior of the sidebar.

See also scroll only one particular div with browser's main scrollbar.

Solution 9 - Javascript

this disables the scrolling on the window if you enter the selector element. works like charms.

elements = $(".selector");

elements.on('mouseenter', function() {
    window.currentScrollTop = $(window).scrollTop();
    window.currentScrollLeft = $(window).scrollTop();
    $(window).on("scroll.prevent", function() {
        $(window).scrollTop(window.currentScrollTop);
        $(window).scrollLeft(window.currentScrollLeft);
    });
});

elements.on('mouseleave', function() {
    $(window).off("scroll.prevent");
});

Solution 10 - Javascript

You can inactivate the scrolling of the whole page by doing something like this but display the scrollbar!

<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>

Solution 11 - Javascript

$this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
  var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
  var scrollTop = this.scrollTop;
  if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
    e.preventDefault();
  }
});

Solution 12 - Javascript

Based on ceed's answer, here is a version that allows nesting scroll guarded elements. Only the element the mouse is over will scroll, and it scrolls quite smoothly. This version is also re-entrant. It can be used multiple times on the same element and will correctly remove and reinstall the handlers.

jQuery.fn.scrollGuard = function() {
	this
		.addClass('scroll-guarding')
		.off('.scrollGuard').on('mouseenter.scrollGuard', function() {
			var $g = $(this).parent().closest('.scroll-guarding');
			$g = $g.length ? $g : $(window);
			$g[0].myCst = $g.scrollTop();
			$g[0].myCsl = $g.scrollLeft();
			$g.off("scroll.prevent").on("scroll.prevent", function() {
				$g.scrollTop($g[0].myCst);
				$g.scrollLeft($g[0].myCsl);
			});
		})
		.on('mouseleave.scrollGuard', function() {
			var $g = $(this).parent().closest('.scroll-guarding');
			$g = $g.length ? $g : $(window);
			$g.off("scroll.prevent");
		});
};

One easy way to use is to add a class, such as scroll-guard, to all the elements in the page that you allow scrolling on. Then use $('.scroll-guard').scrollGuard() to guard them.

Solution 13 - Javascript

If you apply an overflow: hidden style it should go away

edit: actually I read your question wrong, that will only hide the scroll bar but I don't think that's what you are looking for.

Solution 14 - Javascript

I couldn't get any of the answers to work in Chrome and Firefox, so I came up with this amalgamation:

$someElement.on('mousewheel DOMMouseScroll', scrollProtection);

function scrollProtection(event) {
    var $this = $(this);
    event = event.originalEvent;
    var direction = (event.wheelDelta * -1) || (event.detail);
    if (direction < 0) {
        if ($this.scrollTop() <= 0) {
            return false;
        }
    } else {
        if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
            return false;
        }
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeevanView Question on Stackoverflow
Solution 1 - JavascriptTeemuView Answer on Stackoverflow
Solution 2 - JavascriptJeevanView Answer on Stackoverflow
Solution 3 - JavascriptrobisrobView Answer on Stackoverflow
Solution 4 - Javascriptjoe92View Answer on Stackoverflow
Solution 5 - JavascriptPatrick MatteView Answer on Stackoverflow
Solution 6 - JavascriptAndriy StolyarView Answer on Stackoverflow
Solution 7 - JavascriptAlex GolovinView Answer on Stackoverflow
Solution 8 - JavascriptNGLNView Answer on Stackoverflow
Solution 9 - JavascriptceedView Answer on Stackoverflow
Solution 10 - JavascriptjoseantgvView Answer on Stackoverflow
Solution 11 - JavascriptNeil TaylorView Answer on Stackoverflow
Solution 12 - Javascriptd'Artagnan Evergreen BarbosaView Answer on Stackoverflow
Solution 13 - JavascriptJavaKungFuView Answer on Stackoverflow
Solution 14 - Javascriptd.breveView Answer on Stackoverflow