Scrolling within a div without moving page

15,447

Solution 1

This jsfiddle works in Chrome for me. Not tested in other browsers.

Catches the mousewheel event, uses the event data to scroll manually, then cancels the original event. Seems potentially messy for production.

$('#scroll').bind('mousewheel', function(e){

    $(this).scrollTop($(this).scrollTop()-e.originalEvent.wheelDeltaY);

    //prevent page fom scrolling
    return false;    
});

Solution 2

Inspired by Morlem's code, but working the other way around: stop the propagation only if scrolling out. In pure JS:

container.addEventListener('mousewheel', function(e) {
    var scrollingOverTheTop = (e.wheelDelta > 0 && this.scrollTop == 0);
    var scrollingOverTheBottom = (e.wheelDelta < 0 && (this.scrollTop >= this.scrollHeight - this.offsetHeight));
    if (scrollingOverTheBottom || scrollingOverTheTop) {
        e.preventDefault();
        e.stopPropagation();
    }
}, true);

Solution 3

Use a fixed layout. In this jsfiddle I have a working example for it. Study the css. You don't need javascript for it.

Solution 4

And if you do decide to use javascript (again, like KooiInc said, if you don't need js, don't use it), you can try using event.cancelBubble = true, which would prevent the event from propagating to the parent container so the page would not see your inner-div scrolling. Additional command you can use is event.preventDefault(), which prevents browser from triggering default behavior (i.e. scrolling) to the event.

Solution 5

I just solved my issue with this by creating the following in CSS:

body.scroll_locked {
    height: 100%;
    width: 100%;
    overflow: hidden;
}

Then, when I show my modal/lightbox, which is JavaScript (jQuery), I add the scroll_locked class to the body to lock it in place and remove the class to go back. Seems like you could do the same for a mouseenter/mouseleave event for a div that's always on the page and you want to have the same effect.

$('body').addClass('scroll_locked');
$('body').removeClass('scroll_locked');
Share:
15,447
amy
Author by

amy

Updated on June 04, 2022

Comments

  • amy
    amy almost 2 years

    I have a <div id="innerContent"> with overflow-y:scroll;. Links to anchors within innerContent are located on parent page, not in the div.

    So far, I have tried anchors and scrollto's to attempt to scroll within the content. They both complete the scroll, but innerContent's height is larger than the browser window, so the entire parent page also scrolls to the anchor when the links are clicked.

    Is there a way to do this with javascript, without moving the parent page? I do not have control over the height of the div - this is someone else's design.

    This came close... but there isn't an answer here. How to automatic scroll inline div without scrolling the whole page?

    Thank you!

    • cwallenpoole
      cwallenpoole almost 13 years
      Can you just use an iframe? Seems like it might be easier.
    • UserEleventyOne
      UserEleventyOne about 12 years
      Here's a decent answer that uses only Javascript: stackoverflow.com/a/3730577/1374474
  • amy
    amy almost 13 years
    Even with a fixed position layout, I still get a page jump when the div scrolls, if the whole scrolling div isn't in the browser window at the time.
  • amy
    amy almost 13 years
    Actually, I think I've got something in there that's breaking it. When I build from scratch with no bells/whistles, it seems to stay fixed as you say it should.
  • amy
    amy almost 13 years
    Well, after trying all morning, I realized that the css answer won't work. I do still need a vertical scroll bar on the page as well as on the div. I just don't want the page to move when the div content does. I will continue to look for JS solutions.
  • wizonesolutions
    wizonesolutions about 11 years
    Works with position: fixed too. jsfiddle.net/wizonesolutions/Qfk8K, and it does work in Firefox.
  • Andrius Naruševičius
    Andrius Naruševičius about 11 years
    Best solution I've ever found. Should be +1'ed to the sky (works with live too (just replace live with bind)).