24

I'm using the Jquery dialog to open a popup box window on top of a page. When I open the dialog box, I want the general page scrolling to be disabled. To do so, I am doing :

$('body').css({overflow:'hidden'});

when the dialog opens, and:

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

when the dialog closes.

This works but when the scrollbar is being removed, the content in the back moves to the right and the result is not nice.

I tried another method, by creating a css class "noscroll", as such :

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

then, instead of the previous js code, I'm adding and removing this class to the body on dialog open/close.

Now this works for the scrollbar and the content in the back doesn't move to the right, but with this method the content in the back goes back to the top.

So basically method1 makes the content move to the right, and method2 makes the content move back to the top.

Does anyone know a solution for this? no scroll for the content in the back when the dialog opens, and no movement on disabling scrolling...?

Pierre
  • 4,976
  • 12
  • 54
  • 76

6 Answers6

11

I have made a pretty simple example of my solution.

http://jsfiddle.net/6eyJm/1/

Your popup should be in a box

<div id="shadow">
<div id="popup">
    <a id='close' href="#">Close</a>
</div>

Then put those CSS on de root div

#shadow{
    display: none;
    position: fixed;
    top:0;
    bottom: 0;
    width: 100%;
    height:100%;
    background-color: rgba(0,0,0,0.6);
}

Position fixed is really important since you dont want to see the white border, it will take full window width and not body.

Then there's the little JS trick

$('#open').click(function(e){
    e.preventDefault()
    $('body').width($('body').width());
    $('body').css('overflow', 'hidden');
    $('#shadow').css('display', 'block');
})
$('#close').click(function(e){
    e.preventDefault()
    $('body, #shadow').removeAttr('style')
})

The goal here is to take the body width before removing the scroll bar. Your content will not move.

Hope it help!

Sorry for my english, not my native langage.

Karl-André Gagnon
  • 33,662
  • 5
  • 50
  • 75
  • I did a little typo, it shouldnt be $('body #shadow').removeAttr but $('body, #shadow').removeAttr (coma is missing). – Karl-André Gagnon Apr 29 '13 at 14:20
  • 8
    when i put open button at middle of list, then click, page scroll is disabled but it goes back to the top. – Thanh Nguyen Apr 29 '13 at 16:10
  • ok, that's the default function of the a tag. you can change the code of the binding like that $('#open').click(function(e){..} and add in the function e.preventDefault() – Karl-André Gagnon Apr 29 '13 at 16:13
  • 5
    still not working. when open, the scroll position keep there, but when close, it goes back to top again. My code here: `http://jsfiddle.net/ZG8FU/` – Thanh Nguyen Apr 29 '13 at 16:24
  • It do that for the same reason. You need to add the same thing to the # shadow binding! I did it on your fiddle and it work : http://jsfiddle.net/ZG8FU/1/ I hope it will work for you too! – Karl-André Gagnon Apr 29 '13 at 16:31
  • it works fine! Thank you so much! Sorry i speak English not well. – Thanh Nguyen Apr 29 '13 at 16:37
  • This solution still does not stop the arrow keys and pageup/pagedown/end/home from scrolling the original content. This question is being explored in a number of other posts: [one here](http://stackoverflow.com/questions/4770025/how-to-disable-scrolling-temporarily), and [another here](http://stackoverflow.com/questions/2201932/prevent-background-scrolling-when-displaying-popup); plus a number of smaller ones with less promise of finding a solution. None are complete as far as I could tell. – Thomas Oct 09 '13 at 16:14
  • @Thomas That behavior occur only in FF (maybe in IE too, didnt tested) but if you wanna prevent scroll, you can use this : http://jsfiddle.net/6eyJm/10/ – Karl-André Gagnon Oct 09 '13 at 16:51
  • 1
    @TheatreOfSouls The anchor link is scrolling to page to the top. Prevent de default behavior of the link: http://jsfiddle.net/zujv0g36/. – Karl-André Gagnon Aug 12 '19 at 12:51
  • 1
    7 years old post saved my day :) Thanks a lot for the idea, works a treat and honestly I don't see the problem with you're English :D – Emil Borconi Mar 10 '20 at 20:09
9

Remembering the offset should keep your popup at bay;

JSfiddle

HTML

<div id="popupholder">
    <button id="close">Close me</button>
</div>


asd <br />asd <br />asd <br />asd <br />asd <br />
<button class="open">Popup</button>
<br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd<br />
<button class="open">Popup</button>
<br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />
<button class="open">Popup</button>
<br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd<br />
<button class="open">Popup</button>
<br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />asd <br />

CSS

html, body {
    margin: 0px;
}

#popupholder {
    width: 100%;
    height: 100%;
    position: absolute;
    display: box;
    display: -webkit-box;
    display: -moz-box;
    background-color: rgba(0,0,0,0.75);
    display: none;
}

#close {
    display: block;
    height: 20px;
    margin: 75px auto 0px auto;
}

JavaScript

$(document).ready(function() {
    $('.open').click(function() {
        // Block scrolling
        $('body').css('overflow', 'hidden');

        // Show popup
        var offset = window.pageYOffset;
        //console.log(offset);
        $('#popupholder').css({
            'display': 'block',
            'top': offset + 'px'
        });
    });

    $('#close').click(function() {
        // Enable scrolling
        $('body').css('overflow', 'auto');

        // Hide popup
        $('#popupholder').css('display', 'none');
    });
});

For safety-reasons you could add a very high z-index to your #popupholder, but that's not really relevant to the question.

  • Thanks for taking time to write code, but i want disable scroll bar, not hide it like facebook popup. – Thanh Nguyen Apr 22 '13 at 11:06
  • You can add `overflow: hidden;` to the `#popupholder` too. Otherwise you can look into similar variants of WebKit's `::-webkit-scrollbar { display: none; }` styling. It will access the *Shadow DOM* and hide the scrollbar fully. –  Apr 22 '13 at 16:40
3

I had the same problem this repository helped me no-scroll

Azat
  • 1,048
  • 8
  • 9
3

This is the best solution I got so far. And believe me I tried all the others and this is the best and the simplest solution I came up with. It works great on Windows devices, which pushes the page from the right to have room for the system scrollbar and IOS devices which don't require space for their scrollbars in the browsers. So by using this you wont need to add padding on the right so the page doesn't flicker when you hide the overflow of the body or html with css.

The solution is pretty simple if you think about it. The idea is to give the window.scrollTop() the same exact position at the moment that a popup is opened. Also change that position when the window resizes ( as the scroll position changes once that happens ).

So here we go...

First lets create the variable that will let you know that the popup is open and call it stopWindowScroll. If we don't do this then you'll get an error of an undefined variable on your page and set it to 0 - as not active.

$(document).ready(function(){
    stopWindowScroll = 0;
});

Now lets make the open popup function witch can be any function in your code that triggers whatever popup you are using as a plugin or custom. In this case it will be a simple custom popup with a simple document on click function.

$(document).on('click','.open-popup', function(){
    // Saving the scroll position once opening the popup.
    stopWindowScrollPosition = $(window).scrollTop();
    // Setting the stopWindowScroll to 1 to know the popup is open.
    stopWindowScroll = 1;
    // Displaying your popup.
    $('.your-popup').fadeIn(300);
});

So the next thing we do is create the close popup function, which I repeat again can be any function you already have created or are using in a plugin. The important thing is that we need those 2 functions to set the stopWindowScroll variable to 1 or 0 to know when it's open or closed.

$(document).on('click','.open-popup', function(){
    // Setting the stopWindowScroll to 0 to know the popup is closed.
    stopWindowScroll = 0;
    // Hiding your popup
    $('.your-popup').fadeOut(300);
});

Then lets create the window.scroll function so we can prevent the scrolling once the stopWindowScroll mentioned above is set to 1 - as active.

$(window).scroll(function(){
    if(stopWindowScroll == 1) {
         // Giving the window scrollTop() function the position on which
         // the popup was opened, this way it will stay in its place.
         $(window).scrollTop(stopWindowScrollPosition);
    }
});

Thats it. No CSS required for this to work except your own styles for the page. This worked like a charm for me and I hope it helps you and others.

Here is a working example on JSFiddle:

JS Fiddle Example

Let me know if this helped. Regards.

Architect
  • 356
  • 1
  • 5
1

you can calculate the difference between the body width, before and after the overflow hidden, and apply it as padding-right to the body

var bodyStartW = $("body").width();
$("body").css("overflow-y" , "hidden");
var bodyEndW = $("body").width();
var bodyMarginL = bodyEndW - bodyStartW;
$("body").css("padding-right" , bodyMarginL);

In Safari you had the same trick for the "html" tag, and margin-right instead of padding-right

ale
  • 546
  • 4
  • 8
1

I use these two functions for the same purpose:

function enableBodyScroll() {
  if (document.readyState === 'complete') {
    document.body.style.position = '';
    document.body.style.overflowY = '';

    if (document.body.style.marginTop) {
      const scrollTop = -parseInt(document.body.style.marginTop, 10);
      document.body.style.marginTop = '';
      window.scrollTo(window.pageXOffset, scrollTop);
    }
  } else {
    window.addEventListener('load', enableBodyScroll);
  }
}

function disableBodyScroll({ savePosition = false } = {}) {
  if (document.readyState === 'complete') {
    if (document.body.scrollHeight > window.innerHeight) {
      if (savePosition) document.body.style.marginTop = `-${window.pageYOffset}px`;
      document.body.style.position = 'fixed';
      document.body.style.overflowY = 'scroll';
    }
  } else {
    window.addEventListener('load', () => disableBodyScroll({ savePosition }));
  }
}

How it works:

  1. When you want to disable the scroll with saving the current position, you run disableBodyScroll({ savePosition: true }).

  2. The function check whether the page loaded or not (because user may trigger dialog opening during the loading).

  3. If the page is loaded, it saves current scroll position by setting margin-top on body, then it sets position: fixed; overflow-y: scroll on it to remove scrollbar.

  4. If the page isn't loaded, it adds event listener to run (3.) when the page loads.

For enabling scroll everything is the same, but the function remove styles instead of setting them.

Source of the code: https://github.com/funbox/diamonds/blob/master/lib/body-scroll.ts

Igor Adamenko
  • 861
  • 1
  • 8
  • 20