How to programmatically disable page scrolling with jQuery
Asked Answered
P

24

174

Using jQuery, I would like to disable scrolling of the body:

My idea is to:

  1. Set body{ overflow: hidden;}
  2. Capture the current scrollTop();/scrollLeft()
  3. Bind to the body scroll event, set scrollTop/scrollLeft to the captured value.

Is there a better way?


Update:

Please see my example, and a reason why, at http://jsbin.com/ikuma4/2/edit

I am aware someone will be thinking "why does he not just use position: fixed on the panel?".

Please do not suggest this as I have other reasons.

Phosphorite answered 7/9, 2010 at 7:30 Comment(17)
"Is there a better way?" - other than letting the browser behave normally?Abigael
"melodramatically"?Censure
Perhaps meant programmatically? Since it is the firefox top spelling correction suggestion for 'programatically'Tension
A melodrama is what ensues after this happens....Minnich
@Michael, amusing. And my word-smithy tools all agree that this common bit of programming jargon is not actually an accepted English word. I wonder why firefox's speller is suggesting melodramatically.Minnich
PS, I just deliberately did not go edit the title to fix the spell check mistake. Its more fun this way.Minnich
This thread is going \b\Intention
Not just firefox. Google Chrome does the same.Phosphorite
@Sohnee as if 90% of users really know what the normal behavior for their browser is.Jerrold
@Jerrold - well, think of it this way. Your custom implementation will exist on one website. The non custom implementation will exist on millions of websites. Of these two implementations, which one are they more likely to be familiar with?Abigael
@Sohnee dude, my mother wouldn't notice for a second if scrolling were temporarily programmatically disabled if for example some photogallery pops open over her Daily Yoga Routine website. We expect so much more from our browsers than our clients is what I'm sayingJerrold
@Jerrold - I don't think I'm getting your point.Abigael
@Sohnee disabling scrolling !== badJerrold
@Phosphorite For posterity's sake, I think you should include an explanation why position:fixed doesn't work for you. It generally seems like a better approach. -- edit: wait, did you mean position:fixed on the panel/modal, or on the body?Payer
@Lübnah being that I posted this 2 years ago, I have no idea why I couldn't use position fixed ;)Phosphorite
This doesn't stop from scrolling using mouse 3d button.Mange
https://mcmap.net/q/55698/-how-to-disable-scrolling-temporarilyMebane
D
147

The only way I've found to do this is similar to what you described:

  1. Grab current scroll position (don't forget horizontal axis!).
  2. Set overflow to hidden (probably want to retain previous overflow value).
  3. Scroll document to stored scroll position with scrollTo().

Then when you're ready to allow scrolling again, undo all that.

Edit: no reason I can't give you the code since I went to the trouble to dig it up...

// lock scroll position, but retain settings for later
var scrollPosition = [
  self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
  self.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop
];
var html = jQuery('html'); // it would make more sense to apply this to body, but IE7 won't have that
html.data('scroll-position', scrollPosition);
html.data('previous-overflow', html.css('overflow'));
html.css('overflow', 'hidden');
window.scrollTo(scrollPosition[0], scrollPosition[1]);


// un-lock scroll position
var html = jQuery('html');
var scrollPosition = html.data('scroll-position');
html.css('overflow', html.data('previous-overflow'));
window.scrollTo(scrollPosition[0], scrollPosition[1])
Derbent answered 7/9, 2010 at 7:34 Comment(10)
please see jsbin.com/ikuma4/2/edit and explain any reason to me that yours is better? am i missing something (i ask as i can not see any reason for the length of your answer as compared to my example)Phosphorite
Your approach doesn't work in IE7. I tried that first too. The problem is that it doesn't react to the scroll event quickly enough. It lets the document scroll, then snaps it back when your JS resets the scroll position back where you want it.Derbent
Also, if body had an overflow of anything other than auto, it would be overwritten. I needed to preserve the existing setting, so that adds some overhead too.Derbent
Does anyone know why simply styling html and body with overflow: hidden is insufficient? We still end up needing the event handler.Stephanstephana
@Stephanstephana Almost, the body needs to be set to the viewport height. i.e. $('#bodyId').height($(window).height());Orifice
Works in Firefox 14, but not on Android ICS.Madeleinemadelena
This is a fantastic answer. And to make it work on touch devices, check out this answer.Heulandite
using "html" only worked for me in IE. Chrome needed to use "body".Delp
Combined this answer with referenced by @Heulandite and this one to prevent scrolling also on mobile devicesJoelynn
Spent hours looking for a solution and this was the only one that properly disabled scrolling without scrolling to the top of the page first.Recipient
P
258

This will completely disable scrolling:

$('html, body').css({
    overflow: 'hidden',
    height: '100%'
});

To restore:

$('html, body').css({
    overflow: 'auto',
    height: 'auto'
});

Tested it on Firefox and Chrome.

Pattison answered 25/6, 2013 at 9:27 Comment(18)
Still scrolls with middle mouse button on chrome.Metsky
This loses the current scroll position. OP explicitly mentioned about capturing scroll position, so I assume he required that. Anyways, I require it, so this is of limited use to meSynn
PS Omitting the height: 100% effectively locks the scrolling at the current position without the jumping - on latest Chrome, at least.Synn
Kool.. i did used this for one of the overlay on update of qty.for iphone and android.Vincennes
This is NOT the correct answer. Scroll position is not capturedOutrelief
This options hasn't disabled scrolling for me, on Chrome at least.Gilthead
Does not disable scrolling on Chrome.Geomancy
disabled on chrome, but then how to reeable? In developer tools I just unchecked heigh 100% checkboxes, and still I see some disabled scroll bars, not like the page was looking before setting height 100%Audry
This works better than the accepted answer! Thanks! However using "auto" to reenable the scrolling caused the content to disappear for me; replacing "auto" with "" worked instead.Stopgap
@Stopgap auto for overflow or height? Or both?Pattison
@Metsky check my solution which disables middle mouse button tooTribunal
This is the correct answer, thanks. For those who are experiencing two vertical scrollbars when restoring, try $('body').css({ 'overflow': 'auto', 'height': 'auto' });Annoying
This works for me, and removing the height property locks the scroll positionLongplaying
This works perfectly, this is should be the accepted answer.Crane
height: 100% saved me! Thanks. To fix the scroll jumping to top, record the scroll position before making the overlay e.g window.body_scroll_top = $(document).scrollTop();, to restore, $('body').scrollTop(window.body_scroll_top);Snodgrass
Works like a charm. This just reminded that both 'html' and 'body' are equally important.Ellga
definitely should be accepted answer. Simple and after 8 different attempts the only one that worked.Luisaluise
Not working on iPhoneX when I try to block scrolling when angular dialog is opened.Carnot
D
147

The only way I've found to do this is similar to what you described:

  1. Grab current scroll position (don't forget horizontal axis!).
  2. Set overflow to hidden (probably want to retain previous overflow value).
  3. Scroll document to stored scroll position with scrollTo().

Then when you're ready to allow scrolling again, undo all that.

Edit: no reason I can't give you the code since I went to the trouble to dig it up...

// lock scroll position, but retain settings for later
var scrollPosition = [
  self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
  self.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop
];
var html = jQuery('html'); // it would make more sense to apply this to body, but IE7 won't have that
html.data('scroll-position', scrollPosition);
html.data('previous-overflow', html.css('overflow'));
html.css('overflow', 'hidden');
window.scrollTo(scrollPosition[0], scrollPosition[1]);


// un-lock scroll position
var html = jQuery('html');
var scrollPosition = html.data('scroll-position');
html.css('overflow', html.data('previous-overflow'));
window.scrollTo(scrollPosition[0], scrollPosition[1])
Derbent answered 7/9, 2010 at 7:34 Comment(10)
please see jsbin.com/ikuma4/2/edit and explain any reason to me that yours is better? am i missing something (i ask as i can not see any reason for the length of your answer as compared to my example)Phosphorite
Your approach doesn't work in IE7. I tried that first too. The problem is that it doesn't react to the scroll event quickly enough. It lets the document scroll, then snaps it back when your JS resets the scroll position back where you want it.Derbent
Also, if body had an overflow of anything other than auto, it would be overwritten. I needed to preserve the existing setting, so that adds some overhead too.Derbent
Does anyone know why simply styling html and body with overflow: hidden is insufficient? We still end up needing the event handler.Stephanstephana
@Stephanstephana Almost, the body needs to be set to the viewport height. i.e. $('#bodyId').height($(window).height());Orifice
Works in Firefox 14, but not on Android ICS.Madeleinemadelena
This is a fantastic answer. And to make it work on touch devices, check out this answer.Heulandite
using "html" only worked for me in IE. Chrome needed to use "body".Delp
Combined this answer with referenced by @Heulandite and this one to prevent scrolling also on mobile devicesJoelynn
Spent hours looking for a solution and this was the only one that properly disabled scrolling without scrolling to the top of the page first.Recipient
R
47

try this

$('#element').on('scroll touchmove mousewheel', function(e){
  e.preventDefault();
  e.stopPropagation();
  return false;
})
Reverberation answered 20/6, 2014 at 8:7 Comment(6)
just what I was looking for... almost. Anyway to disable it during arrow keys?Attainable
@Attainable - combine this with css overflow: hiddenAudry
@cubbiu how to reverse it ?Mange
You can use $('#element').off('scroll touchmove mousewheel');Stockjobber
Great solution. Although how would you only disable body scrolling yet allow scrolling within other child elements that have overflow: scroll?Peptidase
I have tried every possible solution THIS WORKED ONLY thank you very much!Volution
R
28

you can use this code:

$("body").css("overflow", "hidden");
Robena answered 7/10, 2012 at 9:5 Comment(3)
You can still use the middle mouse button to scroll.Hunch
No, This is ok and no scroll with this!Robena
If you use some extra css you CAN completely disable scrolling, see my answer for more details.Pattison
A
28

I just provide a little tuning to the solution by tfe. In particular, I added some additional control to ensure that there is no shifting of the page content (aka page shift) when the scrollbar is set to hidden.

Two Javascript functions lockScroll() and unlockScroll() can be defined, respectively, to lock and unlock the page scroll.

function lockScroll(){
    $html = $('html'); 
    $body = $('body'); 
    var initWidth = $body.outerWidth();
    var initHeight = $body.outerHeight();

    var scrollPosition = [
        self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
        self.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop
    ];
    $html.data('scroll-position', scrollPosition);
    $html.data('previous-overflow', $html.css('overflow'));
    $html.css('overflow', 'hidden');
    window.scrollTo(scrollPosition[0], scrollPosition[1]);   

    var marginR = $body.outerWidth()-initWidth;
    var marginB = $body.outerHeight()-initHeight; 
    $body.css({'margin-right': marginR,'margin-bottom': marginB});
} 

function unlockScroll(){
    $html = $('html');
    $body = $('body');
    $html.css('overflow', $html.data('previous-overflow'));
    var scrollPosition = $html.data('scroll-position');
    window.scrollTo(scrollPosition[0], scrollPosition[1]);    

    $body.css({'margin-right': 0, 'margin-bottom': 0});
}

where I assumed that the <body> has no initial margin.

Notice that, while the above solution works in most of the practical cases, it is not definitive since it needs some further customization for pages that include, for instance, an header with position:fixed. Let's go into this special case with an example. Suppose to have

<body>
<div id="header">My fixedheader</div>
<!--- OTHER CONTENT -->
</body>

with

#header{position:fixed; padding:0; margin:0; width:100%}

Then, one should add the following in functions lockScroll() and unlockScroll():

function lockScroll(){
    //Omissis   


    $('#header').css('margin-right', marginR);
} 

function unlockScroll(){
    //Omissis   

    $('#header').css('margin-right', 0);
}

Finally, take care of some possible initial value for the margins or paddings.

Ambitendency answered 11/3, 2013 at 14:38 Comment(2)
You have an error in your javascript $body.css({'margin-right': 0, 'margin-bottom', 0}); should be $body.css({'margin-right': 0, 'margin-bottom': 0});Amberambergris
Actually, just use marginRight and marginLeft :)Lungan
H
24

To turn OFF scrolling try this:

var current = $(window).scrollTop();
$(window).scroll(function() {
    $(window).scrollTop(current);
});

to reset:

$(window).off('scroll');
Holomorphic answered 10/4, 2015 at 14:31 Comment(1)
@EveryScreamer no, it makes the screen shake like crazy. Trying to find a workaround.Hellcat
T
5

I've written a jQuery plugin to handle this: $.disablescroll.

It prevents scrolling from mousewheel, touchmove, and keypress events, such as Page Down.

There's a demo here.

Usage:

$(window).disablescroll();

// To re-enable scrolling:
$(window).disablescroll("undo");
Tainataint answered 28/3, 2014 at 12:8 Comment(4)
I've tried to use your disablescroll() plugin to temporarily disable scrolling on hearing the mouswheel/scroll event, but it doesn't work. Any chance you know a way to achieve that effect?Felicitous
@J.B. I can probably help, but comments are not the best place. Join me in this stack overflow chat and I'll see what I can do: chat.stackoverflow.com/rooms/55043/disablescroll-usageTainataint
I'm sorry, but this plugin doesn't even work in your jsfiddle.Arletha
You can help me to inspect this by telling me which browser/platform it doesn't seem to work in please?Tainataint
F
5

You can attach a function to scroll events and prevent its default behaviour.

var $window = $(window);

$window.on("mousewheel DOMMouseScroll", onMouseWheel);

function onMouseWheel(e) {
    e.preventDefault();
}

https://jsfiddle.net/22cLw9em/

Forcier answered 18/6, 2016 at 11:41 Comment(1)
It works. Just needs the reset code posted to match Patricks answerImmigrant
T
4

One liner to disable scrolling including middle mouse button.

$(document).scroll(function () { $(document).scrollTop(0); });

edit: There's no need for jQuery anyway, below same as above in vanilla JS(that means no frameworks, just JavaScript):

document.addEventListener('scroll', function () { this.documentElement.scrollTop = 0; this.body.scrollTop = 0; })

this.documentElement.scrollTop - standard

this.body.scrollTop - IE compatibility

Tribunal answered 27/5, 2015 at 10:22 Comment(0)
D
4
  • To Hide Scroll: $("body").css("overflow", "hidden");
  • To Restore Scroll: $("body").css("overflow", "initial");
Degraw answered 18/10, 2017 at 18:33 Comment(0)
G
3

Can't you just set the body height to 100% and overflow hidden? See http://jsbin.com/ikuma4/13/edit

Gradual answered 17/5, 2011 at 5:59 Comment(1)
$("html").css({ height: '100%', overflow: 'hidden' }); It simply works, thank you AdrianToots
L
3

Somebody posted this code, which has the problem of not retaining the scroll position when restored. The reason is that people tend to apply it to html and body or just the body but it should be applied to html only. This way when restored the scroll position will be kept:

$('html').css({
    'overflow': 'hidden',
    'height': '100%'
});

To restore:

$('html').css({
    'overflow': 'auto',
    'height': 'auto'
});
Laminated answered 7/9, 2015 at 15:16 Comment(2)
not 'overflow': 'auto', use 'overflow': 'initial',Increasing
@Increasing this is what i'm missing . thanksEthanol
C
2

This may or may not work for your purposes, but you can extend jScrollPane to fire other functionality before it does its scrolling. I've only just tested this a little bit, but I can confirm that you can jump in and prevent the scrolling entirely. All I did was:

  • Download the demo zip: http://github.com/vitch/jScrollPane/archives/master
  • Open the "Events" demo (events.html)
  • Edit it to use the non-minified script source: <script type="text/javascript" src="script/jquery.jscrollpane.js"></script>
  • Within jquery.jscrollpane.js, insert a "return;" at line 666 (auspicious line number! but in case your version differs slightly, this is the first line of the positionDragY(destY, animate) function

Fire up events.html, and you'll see a normally scrolling box which due to your coding intervention won't scroll.

You can control the entire browser's scrollbars this way (see fullpage_scroll.html).

So, presumably the next step is to add a call to some other function that goes off and does your anchoring magic, then decides whether to continue with the scroll or not. You've also got API calls to set scrollTop and scrollLeft.

If you want more help, post where you get up to!

Hope this has helped.

Clydesdale answered 17/5, 2011 at 5:37 Comment(0)
C
2

I put an answer that might help here: jQuery simplemodal disable scrolling

It shows how to turn off the scroll bars without shifting the text around. You can ignore the parts about simplemodal.

Compiler answered 20/6, 2011 at 14:33 Comment(0)
A
1

If you just want to disable scrolling with keyboard navigation, you can override keydown event.

$(document).on('keydown', function(e){
    e.preventDefault();
    e.stopPropagation();
});
Argentine answered 27/7, 2015 at 13:14 Comment(0)
P
1

Try this code:

    $(function() { 
        // ...

        var $body = $(document);
        $body.bind('scroll', function() {
            if ($body.scrollLeft() !== 0) {
                $body.scrollLeft(0);
            }
        });

        // ...
    });
Pesticide answered 28/6, 2016 at 1:39 Comment(0)
U
1

I am using the following code to disable scrolling and it works fine

    $('html').css({
      'overflow': 'hidden',
      'height': '100%'
    });

except that on my android tablet, url address bar and top window tags remain visible, and when users scroll up and down, the window also scrolls for about 40px up and down, and shows/hides the url bar and the tags. Is there a way to prevent that and have scrolling fully disabled ?

Unwarrantable answered 8/11, 2020 at 19:23 Comment(0)
A
0

You can cover-up the window with a scrollable div for preventing scrolling of the content on a page. And, by hiding and showing, you can lock/unlock your scroll.

Do something like this:

#scrollLock {
    width: 100%;
    height: 100%;
    position: fixed;
    overflow: scroll;
    opacity: 0;
    display:none
}

#scrollLock > div {
    height: 99999px;
}

function scrollLock(){
    $('#scrollLock').scrollTop('10000').show();
}

function scrollUnlock(){
    $('#scrollLock').hide();
}
Achene answered 15/10, 2012 at 22:54 Comment(1)
Please don't use abbreviations like "u" and "smth". Take the time to spell correctly, for readability.Diskson
P
0

For folks who have centered layouts (via margin:0 auto;), here's a mash-up of the position:fixed solution along with @tfe's proposed solution.

Use this solution if you're experiencing page-snapping (due to the scrollbar showing/hiding).

// lock scroll position, but retain settings for later
var scrollPosition = [
    window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
    window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop
];
var $html = $('html'); // bow to the demon known as MSIE(v7)
$html.addClass('modal-noscroll');
$html.data('scroll-position', scrollPosition);
$html.data('margin-top', $html.css('margin-top'));
$html.css('margin-top', -1 * scrollPosition[1]);

…combined with…

// un-lock scroll position
var $html = $('html').removeClass('modal-noscroll');
var scrollPosition = $html.data('scroll-position');
var marginTop = $html.data('margin-top');
$html.css('margin-top', marginTop);
window.scrollTo(scrollPosition[0], scrollPosition[1])

…and finally, the CSS for .modal-noscroll

.modal-noscroll
{
    position: fixed;
    overflow-y: scroll;
    width: 100%;
}

I would venture to say this is more of a proper fix than any of the other solutions out there, but I haven't tested it that thoroughly yet… :P


Edit: please note that I have no clue how badly this might perform (read: blow up) on a touch device.

Payer answered 17/4, 2013 at 1:59 Comment(0)
M
0

You can also use DOM to do so. Say you have a function you call like this:

function disable_scroll() {
document.body.style.overflow="hidden";
}

And that's all there is to it! Hope this helps in addition to all the other answers!

Millpond answered 30/4, 2014 at 21:52 Comment(0)
R
0

This is what I ended up doing:

CoffeeScript:

    $("input").focus ->
        $("html, body").css "overflow-y","hidden"
        $(document).on "scroll.stopped touchmove.stopped mousewheel.stopped", (event) ->
            event.preventDefault()

    $("input").blur ->
        $("html, body").css "overflow-y","auto"
        $(document).off "scroll.stopped touchmove.stopped mousewheel.stopped"

Javascript:

$("input").focus(function() {
 $("html, body").css("overflow-y", "hidden");
 $(document).on("scroll.stopped touchmove.stopped mousewheel.stopped", function(event) {
   return event.preventDefault();
 });
});

$("input").blur(function() {
 $("html, body").css("overflow-y", "auto");
 $(document).off("scroll.stopped touchmove.stopped mousewheel.stopped");
});
Rubberneck answered 21/7, 2014 at 6:37 Comment(0)
Y
0

Not sure if anybody has tried out my solution. This one works on the whole body/html but no doubt it can be applied to any element that fires a scroll event.

Just set and unset scrollLock as you need.

var scrollLock = false;
var scrollMem = {left: 0, top: 0};

$(window).scroll(function(){
    if (scrollLock) {
        window.scrollTo(scrollMem.left, scrollMem.top);
    } else {
        scrollMem = {
            left: self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
            top: self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
        };
    }
});

Here's the example JSFiddle

Hope this one helps somebody.

Yip answered 20/11, 2014 at 9:32 Comment(1)
This one works as it should, with one exception. When the scroll is locked, and i scroll, it kinda twitches a little, before actually locking the scroll...Jaddan
R
0

I think the best and clean solution is:

window.addEventListener('scroll',() => {
    var x = window.scrollX;
    var y = window.scrollY;
    window.scrollTo(x,y);
});

And with jQuery:

$(window).on('scroll',() => {
    var x = window.scrollX;
    var y = window.scrollY;
    window.scrollTo(x,y)
})

Those event listener should block scrolling. Just remove them to re enable scrolling

Rothberg answered 20/6, 2018 at 13:36 Comment(0)
M
0

If want to programmatically disable scrolling you can use:

overflow: clip;

If you wanted to disable scrolling for the user you can use:

overflow: hidden;

https://developer.mozilla.org/en-US/docs/Web/CSS/overflow

The browser support for the overflow property varies:

https://caniuse.com/?search=overflow

Maurizia answered 20/4, 2021 at 15:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.