13

I have a div that is scrollable, but whenever you reach the bottom/top of it, it begins to scroll the entire page. That could be annoying for users who scroll fast, and then the entire page starts scrolling unexpectedly.

I need something where if you are hovering over the div, the page is not scrollable.

I have tried this by adding CSS when I hover the div...

body {
    overflow:hidden;
}

...It works but there is one problem. The scrollbar disappears and that looks kind of stupid to have it disappearing/reappearing. Any way to achieve the same effect but keep the scrollbar visible? I have seen it done with Facebook chat.

TJE
  • 240
  • 1
  • 4
  • 14
  • 1
    it is very similar, but i hate solutions that involve use of adding a plugin, especially for something this simple. it can be done better. – PlantTheIdea May 01 '13 at 18:18

2 Answers2

29

Here is a very simple way to stop the propagation with no plugins, just jQuery.

Update: The code has been updated to work correctly in IE9+. Have not tested in previous versions.

First, create a class on your <div> to mark it as having this behavior. In my example, I use the class .Scrollable.

<div class="Scrollable">
  <!-- A bunch of HTML here which will create scrolling -->
</div>

The jQuery to disable is:

$('.Scrollable').on('DOMMouseScroll mousewheel', function(ev) {
    var $this = $(this),
        scrollTop = this.scrollTop,
        scrollHeight = this.scrollHeight,
        height = $this.height(),
        delta = (ev.type == 'DOMMouseScroll' ?
            ev.originalEvent.detail * -40 :
            ev.originalEvent.wheelDelta),
        up = delta > 0;

    var prevent = function() {
        ev.stopPropagation();
        ev.preventDefault();
        ev.returnValue = false;
        return false;
    }

    if (!up && -delta > scrollHeight - height - scrollTop) {
        // Scrolling down, but this will take us past the bottom.
        $this.scrollTop(scrollHeight);
        return prevent();
    } else if (up && delta > scrollTop) {
        // Scrolling up, but this will take us past the top.
        $this.scrollTop(0);
        return prevent();
    }
});

In essence, what this does is to detect which direction the scrolling is being requested in (based on the originalEvent.wheelDelta: positive = up, negative = down). If the requested delta of the mousewheel event would move scrolling past the top or bottom of the <div>, cancel the event.

In IE, especially, scrolling events which go past a child element's scrollable area then roll up to parent elements, and the scrolling continues regardless of the event being canceled. Because we cancel the event in any case, and then control the scrolling on the child through jQuery, this is prevented.

This is loosely based on the way that this question solves the problem, but does not require the plugin, and is cross-browser compliant with IE9+.

Here is a working jsFiddle demonstrating the code in-action.

Here is a working jsFiddle demonstrating the code in-action, and updated to work with IE.

Here is a working jsFiddle demonstrating the code in-action, and updated to work with IE and FireFox. See this post for more details about the necessity of the changes.

Community
  • 1
  • 1
Troy Alford
  • 26,660
  • 10
  • 64
  • 82
  • 1
    I was excited to see this simple solution (that worked in google chrome) at first, but then I tried the fiddle in IE9. IE just keeps disappointing us :@ – Ejaz May 01 '13 at 19:12
  • @Ejay could the IE9 problems be related to using this.scrollTop/Height instead of $(this).scrollTop()/Height()? I think this.scrollTop is always 0 in IE? – Kato May 01 '13 at 19:29
  • Good work. It's working when I scroll up, but not down. I think it's returning the wrong scrollTop value, so I'll have to look into that for my particular situation. – TJE May 01 '13 at 20:01
  • Thomas: can you put up a fiddle of your code? – Troy Alford May 01 '13 at 20:48
  • 1
    Works fine now. My scrollHeight was off by 20 because of something I had in there so I just added "-20" and it's good. – TJE May 01 '13 at 21:21
  • 2
    @Ejay: I updated the code to work with IE. :) @Kato: good thought, but that wasn't it. It had to do with IE not honoring a canceled `mousewheel` event when the `delta` is greater than the available scrolling height. Ridiculous - but the updated code fixes it. – Troy Alford May 01 '13 at 21:24
  • @Thomas: If this solved your problem, please mark it as the correct answer by clicking the check mark next to it. :) – Troy Alford May 01 '13 at 21:26
  • One more update - because my code didn't work in FireFox. :P lol... the newest version does. – Troy Alford May 01 '13 at 21:51
  • Thanks! Work in IE, FF, Chrome. Beautiful! – Jobi Carter Dec 05 '13 at 20:20
  • Doesn't work in Firefox 26 mac. It looks like eventually the scroll event buffer overflows or something, or that it doesn't work when also scrolling horizontal too (touch pad, mighty mouse) – GDmac Jan 10 '14 at 17:01
  • 1
    Sadly this also does not work with iFrame's in IE9 or IE10 on Windows 7. Haven't tested anywhere else. No problems in Chrome, Firefox, or Opera. – jkupczak Mar 12 '14 at 11:48
  • Can't believe how easy it was. Working on Firefox 109.0 – Pepv Feb 15 '23 at 18:42
1

maybe have a look to

How to disable scrolling temporarily?

This is a sample to stop and activate scroll

Community
  • 1
  • 1
  • I think this disables all scrolling. I want to keep the div element scrollable. – TJE May 01 '13 at 18:31