I want my body to stop scrolling when using the mousewheel while the Modal (from http://twitter.github.com/bootstrap) on my website is opened.
I've tried to call the piece of javascript below when the modal is opened but without success
$(window).scroll(function() { return false; });
AND
$(window).live('scroll', function() { return false; });
Please note our website dropped support for IE6, IE7+ needs to be compatible though.
Bootstrap's modal
automatically adds the class modal-open
to the body when a modal dialog is shown and removes it when the dialog is hidden. You can therefore add the following to your CSS:
body.modal-open {
overflow: hidden;
}
You could argue that the code above belongs to the Bootstrap CSS code base, but this is an easy fix to add it to your site.
Update 8th feb, 2013
This has now stopped working in Twitter Bootstrap v. 2.3.0 -- they no longer add the modal-open
class to the body.
A workaround would be to add the class to the body when the modal is about to be shown, and remove it when the modal is closed:
$("#myModal").on("show", function () {
$("body").addClass("modal-open");
}).on("hidden", function () {
$("body").removeClass("modal-open")
});
Update 11th march, 2013 Looks like the modal-open
class will return in Bootstrap 3.0, explicitly for the purpose of preventing the scroll:
Reintroduces .modal-open on the body (so we can nuke the scroll there)
See this: https://github.com/twitter/bootstrap/pull/6342 - look at the Modal section.
The accepted answer doesn't work on mobile (iOS 7 w/ Safari 7, at least) and I don't want MOAR JavaScript running on my site when CSS will do.
This CSS will prevent the background page from scrolling under the modal:
body.modal-open {
overflow: hidden;
position: fixed;
}
However, it also has a slight side-affect of essentially scrolling to the top. position:absolute
resolves this but, re-introduces the ability to scroll on mobile.
If you know your viewport (my plugin for adding viewport to the <body>
) you can just add a css toggle for the position
.
body.modal-open {
// block scroll for mobile;
// causes underlying page to jump to top;
// prevents scrolling on all screens
overflow: hidden;
position: fixed;
}
body.viewport-lg {
// block scroll for desktop;
// will not jump to top;
// will not prevent scroll on mobile
position: absolute;
}
I also add this to prevent the underlying page from jumping left/right when showing/hiding modals.
body {
// STOP MOVING AROUND!
overflow-x: hidden;
overflow-y: scroll !important;
}
position: fixed
on the body.
js const currPageScrollPos = $(window).scrollTop() $("body").removeClass("show_overlay") $(window).delay(5).scrollTop(currPageScrollPos)
Simply hide the body overflow and it makes body not scrolling. When you hide the modal, revert it to automatic.
Here is the code:
$('#adminModal').modal().on('shown', function(){
$('body').css('overflow', 'hidden');
}).on('hidden', function(){
$('body').css('overflow', 'auto');
})
You need to go beyond @charlietfl's answer and account for scrollbars, otherwise you may see a document reflow.
Opening the modal:
Record the body width Set body overflow to hidden Explicitly set the body width to what it was in step 1. var $body = $(document.body); var oldWidth = $body.innerWidth(); $body.css("overflow", "hidden"); $body.width(oldWidth);
Closing the modal:
Set body overflow to auto Set body width to auto var $body = $(document.body); $body.css("overflow", "auto"); $body.width("auto");
Inspired by: http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
$body.css("overflow", "auto");
in the last step :)
You could try setting body size to window size with overflow: hidden when modal is open
Warning: The option below is not relevant to Bootstrap v3.0.x, as scrolling in those versions has been explicitly confined to the modal itself. If you disable wheel events you may inadvertently prevent some users from viewing the content in modals that have heights greater than the viewport height.
Yet Another Option: Wheel Events
The scroll event is not cancelable. However it is possible to cancel the mousewheel and wheel events. The big caveat is that not all legacy browsers support them, Mozilla only recently adding support for the latter in Gecko 17.0. I don't know the full spread, but IE6+ and Chrome do support them.
Here's how to leverage them:
$('#myModal')
.on('shown', function () {
$('body').on('wheel.modal mousewheel.modal', function () {
return false;
});
})
.on('hidden', function () {
$('body').off('wheel.modal mousewheel.modal');
});
JSFiddle
overflow:hidden
is better for now.
Try this one:
.modal-open {
overflow: hidden;
position:fixed;
width: 100%;
height: 100%;
}
it worked for me. (supports IE8)
position: fixed
.
/* =============================
* Disable / Enable Page Scroll
* when Bootstrap Modals are
* shown / hidden
* ============================= */
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
function theMouseWheel(e) {
preventDefault(e);
}
function disable_scroll() {
if (window.addEventListener) {
window.addEventListener('DOMMouseScroll', theMouseWheel, false);
}
window.onmousewheel = document.onmousewheel = theMouseWheel;
}
function enable_scroll() {
if (window.removeEventListener) {
window.removeEventListener('DOMMouseScroll', theMouseWheel, false);
}
window.onmousewheel = document.onmousewheel = null;
}
$(function () {
// disable page scrolling when modal is shown
$(".modal").on('show', function () { disable_scroll(); });
// enable page scrolling when modal is hidden
$(".modal").on('hide', function () { enable_scroll(); });
});
Couldn't make it work on Chrome just by changing CSS, because I didn't want the page to scroll back to the top. This worked fine:
$("#myModal").on("show.bs.modal", function () {
var top = $("body").scrollTop(); $("body").css('position','fixed').css('overflow','hidden').css('top',-top).css('width','100%').css('height',top+5000);
}).on("hide.bs.modal", function () {
var top = $("body").position().top; $("body").css('position','relative').css('overflow','auto').css('top',0).scrollTop(-top);
});
Adding the class 'is-modal-open' or modifying style of body tag with javascript is okay and it will work as supposed to. But the problem we gonna face is when the body becomes overflow:hidden, it will jump to the top, ( scrollTop will become 0 ). This will become a usability issue later.
As a solution for this problem, instead of changing body tag overflow:hidden change it on html tag
$('#myModal').on('shown.bs.modal', function () {
$('html').css('overflow','hidden');
}).on('hidden.bs.modal', function() {
$('html').css('overflow','auto');
});
As of November 2017 Chrome Introduced a new css property
overscroll-behavior: contain;
which solves this problem although as of writing has limited cross browser support.
see below links for full details and browser support
https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior
https://developers.google.com/web/updates/2017/11/overscroll-behavior
For Bootstrap, you might try this (working on Firefox, Chrome and Microsoft Edge) :
body.modal-open {
overflow: hidden;
position:fixed;
width: 100%;
}
Hope this helps...
I'm not sure about this code, but it's worth a shot.
In jQuery:
$(document).ready(function() {
$(/* Put in your "onModalDisplay" here */)./* whatever */(function() {
$("#Modal").css("overflow", "hidden");
});
});
As I said before, I'm not 100% sure but try anyway.
I'm not 100% sure this will work with Bootstrap but worth a try - it worked with Remodal.js which can be found on github: http://vodkabears.github.io/remodal/ and it would make sense for the methods to be pretty similar.
To stop the page jumping to the top and also prevent the right shift of content add a class to the body
when the modal is fired and set these CSS rules:
body.with-modal {
position: static;
height: auto;
overflow-y: hidden;
}
It's the position:static
and the height:auto
that combine to stop the jumping of content to the right. The overflow-y:hidden;
stops the page from being scrollable behind the modal.
The best solution is the css-only body{overflow:hidden}
solution used by most of these answers. Some answers provide a fix that also prevent the "jump" caused by the disappearing scrollbar; however, none were too elegant. So, I wrote these two functions, and they seem to work pretty well.
var $body = $(window.document.body);
function bodyFreezeScroll() {
var bodyWidth = $body.innerWidth();
$body.css('overflow', 'hidden');
$body.css('marginRight', ($body.css('marginRight') ? '+=' : '') + ($body.innerWidth() - bodyWidth))
}
function bodyUnfreezeScroll() {
var bodyWidth = $body.innerWidth();
$body.css('marginRight', '-=' + (bodyWidth - $body.innerWidth()))
$body.css('overflow', 'auto');
}
Check out this jsFiddle to see it in use.
open modal
buttons' width. Chrome on 8
React , if you are looking for
useEffect in the modal that is getting popedup
useEffect(() => {
document.body.style.overflowY = 'hidden';
return () =>{
document.body.style.overflowY = 'auto';
}
}, [])
Many suggest "overflow: hidden" on the body, which will not work (not in my case at least), since it will make the website scroll to the top.
This is the solution that works for me (both on mobile phones and computers), using jQuery:
$('.yourModalDiv').bind('mouseenter touchstart', function(e) {
var current = $(window).scrollTop();
$(window).scroll(function(event) {
$(window).scrollTop(current);
});
});
$('.yourModalDiv').bind('mouseleave touchend', function(e) {
$(window).off('scroll');
});
This will make the scrolling of the modal to work, and prevent the website from scrolling at the same time.
I had to set the viewport-height to get this working perfectly
body.modal-open {
height: 100vh;
overflow: hidden;
}
You could use the following logic, I tested it and it works(even in IE)
<html>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">
var currentScroll=0;
function lockscroll(){
$(window).scrollTop(currentScroll);
}
$(function(){
$('#locker').click(function(){
currentScroll=$(window).scrollTop();
$(window).bind('scroll',lockscroll);
})
$('#unlocker').click(function(){
currentScroll=$(window).scrollTop();
$(window).unbind('scroll');
})
})
</script>
<div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<button id="locker">lock</button>
<button id="unlocker">unlock</button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
</div>
Based on this fiddle: http://jsfiddle.net/dh834zgw/1/
the following snippet (using jquery) will disable the window scroll:
var curScrollTop = $(window).scrollTop();
$('html').toggleClass('noscroll').css('top', '-' + curScrollTop + 'px');
And in your css:
html.noscroll{
position: fixed;
width: 100%;
top:0;
left: 0;
height: 100%;
overflow-y: scroll !important;
z-index: 10;
}
Now when you remove the modal, don't forget to remove the noscroll class on the html tag:
$('html').toggleClass('noscroll');
overflow
be set to hidden
? +1 though as this worked for me (using hidden
).
Sadly none of the answers above fixed my issues.
In my situation, the web page originally has a scroll bar. Whenever I click the modal, the scroll bar won't disappear and the header will move to right a bit.
Then I tried to add .modal-open{overflow:auto;}
(which most people recommended). It indeed fixed the issues: the scroll bar appears after I open the modal. However, another side effect comes out which is that "background below the header will move to the left a bit, together with another long bar behind the modal"
https://i.stack.imgur.com/qZa3y.png
Luckily, after I add {padding-right: 0 !important;}
, everything is fixed perfectly. Both the header and body background didn't move and the modal still keeps the scrollbar.
https://i.stack.imgur.com/AzzuA.png
Hope this can help those who are still stuck with this issue. Good luck!
This worked for me:
$("#mymodal").mouseenter(function(){
$("body").css("overflow", "hidden");
}).mouseleave(function(){
$("body").css("overflow", "visible");
});
Most of the pieces are here, but I don't see any answer that puts it all together.
The problem is threefold.
(1) prevent the scroll of the underlying page
$('body').css('overflow', 'hidden')
(2) and remove the scroll bar
var handler = function (e) { e.preventDefault() }
$('.modal').bind('mousewheel touchmove', handler)
(3) clean up when the modal is dismissed
$('.modal').unbind('mousewheel touchmove', handler)
$('body').css('overflow', '')
If the modal is not full-screen then apply the .modal bindings to a full screen overlay.
My solution for Bootstrap 3:
.modal {
overflow-y: hidden;
}
body.modal-open {
margin-right: 0;
}
because for me the only overflow: hidden
on the body.modal-open
class did not prevent the page from shifting to the left due to the original margin-right: 15px
.
I just done it this way ...
$('body').css('overflow', 'hidden');
But when the scroller dissapeared it moved everything right 20px, so i added
$('body').css('margin-right', '20px');
straight after it.
Works for me.
If modal are 100% height/width "mouseenter/leave" will work to easily enable/disable scrolling. This really worked out for me:
var currentScroll=0;
function lockscroll(){
$(window).scrollTop(currentScroll);
}
$("#myModal").mouseenter(function(){
currentScroll=$(window).scrollTop();
$(window).bind('scroll',lockscroll);
}).mouseleave(function(){
currentScroll=$(window).scrollTop();
$(window).unbind('scroll',lockscroll);
});
I had a sidebar that was generated by checkbox hack. But the main idea is to save the document scrollTop and not to change it during scrolling the window.
I just didn't like the page jumping when body becomes 'overflow: hidden'.
window.addEventListener('load', function() { let prevScrollTop = 0; let isSidebarVisible = false; document.getElementById('f-overlay-chkbx').addEventListener('change', (event) => { prevScrollTop = window.pageYOffset || document.documentElement.scrollTop; isSidebarVisible = event.target.checked; window.addEventListener('scroll', (event) => { if (isSidebarVisible) { window.scrollTo(0, prevScrollTop); } }); }) });
Since for me this problem presented mainly on iOS, I provide the code to fix that only on iOS:
if(!!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)) {
var $modalRep = $('#modal-id'),
startScrollY = null,
moveDiv;
$modalRep.on('touchmove', function(ev) {
ev.preventDefault();
moveDiv = startScrollY - ev.touches[0].clientY;
startScrollY = ev.touches[0].clientY;
var el = $(ev.target).parents('#div-that-scrolls');
// #div-that-scrolls is a child of #modal-id
el.scrollTop(el.scrollTop() + moveDiv);
});
$modalRep.on('touchstart', function(ev) {
startScrollY = ev.touches[0].clientY;
});
}
None of the above answers worked perfectly for me. So I found another way which works well.
Just add a scroll.(namespace)
listener and set scrollTop
of the document
to the latest of it's value...
and also remove the listener in your close script.
// in case of bootstrap modal example:
$('#myModal').on('shown.bs.modal', function () {
var documentScrollTop = $(document).scrollTop();
$(document).on('scroll.noScroll', function() {
$(document).scrollTop(documentScrollTop);
return false;
});
}).on('hidden.bs.modal', function() {
$(document).off('scroll.noScroll');
});
update
seems, this does not work well on chrome. any suggestion to fix it ?
This works
body.modal-open {
overflow: hidden !important;
}
Success story sharing
modal-open
will return in Bootstrap 3, so when that launches it should be safe to remove the above code.