5

Simply put, i guess you all know the issue: you use your mousewheel (or trackpad gesture) to scroll inside a div that is set to overflow:scroll (or a setting to that effect). The moment you reach the end of the scrollable area, the scroll 'commands' are immediately sent to the parent container - the main window for instance.

This can be quite annoying and i wonder if there is a way to prevent it.

I created this jsFiddle to demonstrate the issue and provide a ground for experimentation.

The only idea that came to my mind was using preventDefault but since i am not a JS wizard, i don't see where or how i could apply that correctly.

SquareCat
  • 5,318
  • 5
  • 33
  • 74
  • You can't really prevent scrolling, that would be really annoying in some cases, best you can do is remove the scrollbars. – adeneo Mar 09 '14 at 20:13
  • With all due respect, i must disagree. There are certain situations in which it would make sense to apply it, such as in specific backend user interface environments. Also, i remain certain there is some way to accomplish it. After all it must be possible to somehow catch the mousewheel interactions. – SquareCat Mar 09 '14 at 20:14
  • It didn't say it wouldn't be useful, I said it would be annoying in some cases, as in when misused. – adeneo Mar 09 '14 at 20:18
  • That is correct. Let's say it's fragile grounds to walk on ;) But nevertheless, i need to find a solution. – SquareCat Mar 09 '14 at 20:19
  • I don't think there is one, Facebook removes the scrollbars in some cases when showing dialogs, and if there where a way to just disable scrolling, I'm pretty sure they would have figured it out. – adeneo Mar 09 '14 at 20:21
  • I wouldn't put that much trust in a pile of sugar. – SquareCat Mar 09 '14 at 20:22

2 Answers2

5

This is not optimal but I bootstrap uses this for their modal windows.

FIDDLE

.overflowHidden {
    overflow:hidden !important;
}

$('#scrollable').hover(function () {
        console.log("hello");
        $('body').addClass('overflowHidden');
    }, function () {
        $('body').removeClass('overflowHidden');
    });
Lokesh Suthar
  • 3,153
  • 1
  • 13
  • 28
  • Actually, that's a pretty smart approach! Gratitude! I like it. I'm gonna test it a bit further, but i think this does the job! – SquareCat Mar 09 '14 at 22:20
  • Let me know if you find any bugs while testing. – Lokesh Suthar Mar 09 '14 at 22:22
  • That's cool, just want to throw in, that the scrolling with my ThinkPad scrolling (you know, the red "button") sometimes seems not to work at all (the scrollbar of the div just jumps down) and sometimes it is verry sloooow! – loveNoHate Mar 09 '14 at 22:29
  • I am not sure if I understand that. But one thing is clear, this doesn't change the scrolling behavior, so I guess something else must be screwing it up. – Lokesh Suthar Mar 09 '14 at 22:38
  • Alright, so i tested it. Generally it can be seen as a proper workaround and surely the effort (@LokeshSuthar) deserves some credit. Nevertheless, i cannot use it in my live environment due to several reasons. I'll keep looking for a more precise solution, so to speak. I just by accident discovered [a site](http://harvesthq.github.io/chosen/) that seems to incorporate some effective method. If you try scrolling the custom selectbox, you'll notice it will not have the scrolling continue in the outer parent, once the bottom is reached. I'll look into how it's done there. – SquareCat Mar 10 '14 at 22:50
  • Can you tell me what stopped you from using this? I wanted to use this myself, you made me doubt it :P – Lokesh Suthar Mar 11 '14 at 06:38
  • In my case there were problems with wrapper containers adapting to the changes in document behaviour when it was set to `overflow:hidden`. Also, i didn't like the idea of making major changes to the main document body, as this approach is unsafe and feels a bit like too much of a workaround. – SquareCat Mar 11 '14 at 18:21
  • The problems that could occur (i could not think of one) with that approach can be fixed for sure with proper css i would say. For me, this approach feels safe and good enough to actually implement it in production. Congrats for this nice, creative idea and thanks for sharing! :) – jebbie Nov 05 '14 at 09:01
2

After extensive research and violent testing, i combined my results into a solution that serves my purpose perfectly.

The approach is simple

Instead of measuring scroll conditions (on scroll) from within a container, we simply replace the entire scroll functionality by writing our own scroll handler. That way we have complete control over what is happening, plus the scroll event cannot default (or bubble) to the outer container:

Meet greedyScroll v0.9b

$.fn.extend({
    greedyScroll: function(sensitivity) {
        return this.each(function() {
            $(this).bind('mousewheel DOMMouseScroll', function(evt) {
               var delta;
               if (evt.originalEvent) {
                  delta = -evt.originalEvent.wheelDelta || evt.originalEvent.detail;
               }
               if (delta !== null) {
                  evt.preventDefault();
                  if (evt.type === 'DOMMouseScroll') {
                     delta = delta * (sensitivity ? sensitivity : 20);
                  }
                  return $(this).scrollTop(delta + $(this).scrollTop());
               }
            });
        });
    }
});

Usage

HTML:

<div class="scrollWrapper"></div>

Javascript:

$('.scrollWrapper').greedyScroll(25);

I found a value of 20 works fine for sensitivity, but some may prefer higher or lower settings.

Disclaimer

I don't claim this works in anything other than Chrome, as this is what i exclusively made sure it works for.

Credits go almost entirely to the team who developed the plugin i linked to in one of the comments to Lokesh's answer.

Code improvements are always welcome.

SquareCat
  • 5,318
  • 5
  • 33
  • 74