打开模式时防止BODY滚动


346

当我的网站上的Modal(来自http://twitter.github.com/bootstrap)打开时,我希望我的身体在使用鼠标滚轮时停止滚动。

我试图在模式打开时调用下面的一段javascript,但没有成功

$(window).scroll(function() { return false; });

$(window).live('scroll', function() { return false; });

请注意,我们的网站已放弃了对IE6的支持,不过IE7 +需要兼容。

Answers:


467

在显示模式对话框时,Bootstrap会modal自动将类添加modal-open到主体,而在对话框隐藏时将其删除。因此,您可以将以下内容添加到CSS中:

body.modal-open {
    overflow: hidden;
}

您可能会争辩说,上面的代码属于Bootstrap CSS代码库,但这是将其添加到您的站点的简便解决方案。

2013年2月8日更新
这已经在Twitter Bootstrap 2.3.0版中停止了工作-他们不再将modal-open类添加到正文中。

一种解决方法是在要显示模式时将类添加到主体,并在关闭模式时将其删除:

$("#myModal").on("show", function () {
  $("body").addClass("modal-open");
}).on("hidden", function () {
  $("body").removeClass("modal-open")
});

2013年3月11日更新 看起来modal-open该类将在Bootstrap 3.0中返回,明确地是为了防止滚动:

在主体上重新引入.modal-open(因此我们可以在此处滚动滚动条)

请参阅:https : //github.com/twitter/bootstrap/pull/6342-查看“ 模态”部分。


2
这在引导2.2.2中不再起作用。希望.modal-open将来会回来... github.com/twitter/bootstrap/issues/5719
ppetrid

2
@ppetrid我不希望它返回。根据本文撰写:github.com/twitter/bootstrap/wiki/Upcoming-3.0-changes(看底部)。Quote:“不再有内部模式滚动。取而代之的是,模式将增长以容纳其内容,而页面滚动将容纳该模式。”
MartinHN 2012年

2
@Bagata Cool- modal-open将会在Bootstrap 3中返回,因此启动时应安全删除上述代码。
MartinHN

2
这就是为什么应该继续向下滚动的原因,如果选择的答案不能使您满意,那么您很可能会找到类似这样的宝石。没想到97个以上的投票答案在其他不受欢迎的评论下如此深入。
Mohd Abdul Mujib 2014年

2
这样做的问题是,为了防止打开模式时文档滚动到顶部,您需要添加body.modal-open {overflow:visible}。您的解决方案目前有效,不利之处在于,一旦打开模式,文档就会滚动到顶部
patrick

120

可接受的答案不适用于移动设备(至少是装有Safari 7的iOS 7和Safari 7),并且我不希望CSS支持时在我的网站上运行MOAR JavaScript。

此CSS可以防止背景页面在模式下滚动:

body.modal-open {
    overflow: hidden;
    position: fixed;
}

但是,它也具有基本滚动到顶部的轻微副作用。position:absolute解决了此问题,但重新引入了在移动设备上滚动的功能。

如果您知道您的视口(我的插件将视口添加到<body>),您只需添加一个CSS切换器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; 
}

我还添加了此选项,以防止显示/隐藏模式时基础页面向左/向右跳转。

body {
    // STOP MOVING AROUND!
    overflow-x: hidden;
    overflow-y: scroll !important;
}

这个答案是x-post。


7
谢谢!手机(至少是iOS和Android本机浏览器)让我头疼,如果没有手机,手机将无法工作position: fixed
劳尔·雷内

感谢您还提供了用于在显示/隐藏模式时防止页面向左/向右跳转的代码。这非常有用,我验证了它可以解决运行iOS 9.2.1的iPhone 5c在Safari上遇到的问题。
伊莱贾·洛夫格伦

6
为了将滚动固定到顶部,您可以在添加类之前记录位置,然后在删除类之后,将window.scroll记录到记录位置。这是我自己修复的方式:pastebin.com/Vpsz07zd
工具

尽管我认为这仅满足非常基本的需求,但这是一个有用的解决方案。谢谢。
史蒂夫·本纳

32

只需隐藏身体溢出,它就不会滚动。隐藏模态时,将其还原为自动模态。

这是代码:

$('#adminModal').modal().on('shown', function(){
    $('body').css('overflow', 'hidden');
}).on('hidden', function(){
    $('body').css('overflow', 'auto');
})

优秀的!这帮助了我。谢谢。
pfcodes

21

您可以尝试将主体大小设置为具有溢出的窗口大小:模式打开时隐藏


12
这样做每次打开模态时都会移动屏幕,这不方便,我只需要禁用背景滚动即可
xorinzor 2012年

不确定滚动条是否与浏览器相关,并且不能对其做太多操作
charlietfl 2012年

您可以将模式设置为“固定”,因此滚动时不会移动
charlietfl 2012年

8
它不是关于停止模态的滚动,而是关于在后台停止体的滚动
xorinzor 2012年

1
如果身体溢出,它就是滚动的窗口。例如,滚动条不是文档的一部分。
charlietfl 2012年

18

您需要超越@charlietfl的答案并考虑滚动条,否则您可能会看到文档重排。

打开模式:

  1. 记录body宽度
  2. body溢出设置为hidden
  3. 将主体宽度显式设置为步骤1中的宽度。

    var $body = $(document.body);
    var oldWidth = $body.innerWidth();
    $body.css("overflow", "hidden");
    $body.width(oldWidth);

关闭模式:

  1. body溢出设置为auto
  2. body宽度设置为auto

    var $body = $(document.body);
    $body.css("overflow", "auto");
    $body.width("auto");

灵感来源:http : //jdsharp.us/jQuery/minute/calculate-scrollbar-width.php


由于缺少更好的术语,我遇到了一个“跳动”的屏幕,这里的关键是按照宽度设置。万分感谢。
Hcabnettek

1
@Hcabnettek是的:“ jumpy” ==“文档重排”。很高兴为您提供帮助!:-)
jpap

为此有一个CSS解决方案?在所有浏览器和移动设备上都可以使用吗?
鲁宾2014年

只是一个拼写错误:它必须$body.css("overflow", "auto");在最后一步:)
schneikai 2015年

天哪,这真是个奇妙的主意。@jpap,您帮助我解决了困扰我很长时间的文档重排问题。
Goran Radulovic

17

警告:以下选项与Bootstrap v3.0.x无关,因为在这些版本中的滚动已明确限于模式本身。如果禁用滚轮事件,则可能会无意间阻止某些用户以高度大于视口高度的模态查看内容。


另一个选择:车轮事件

滚动事件不是取消。但是,可以取消鼠标滚轮滚轮事件。最大的警告是,并非所有旧版浏览器都支持它们,Mozilla最近才在Gecko 17.0中添加了对后者的支持。我不知道它的全部范围,但是IE6 +和Chrome确实支持它们。

利用它们的方法如下:

$('#myModal')
  .on('shown', function () {
    $('body').on('wheel.modal mousewheel.modal', function () {
      return false;
    });
  })
  .on('hidden', function () {
    $('body').off('wheel.modal mousewheel.modal');
  });

JSFiddle


您的JSFiddle无法在Firefox 24,Chrome 24或IE9上运行。
AxeEffect 2013年

@AxeEffect应该现在正在工作。唯一的问题是对Bootstrap库的外部引用已更改。感谢您的注意。
merv

2
这不会阻止触摸设备滚动,overflow:hidden目前更好。
Webinan 2014年

5
它们都可以工作,但不适用于移动设备。-__-测试的Android 4.1和Chrome
塔吉米

@TowerJimmy,您可能需要为此取消触摸或拖动事件(如果可能的话)
xorinzor

9
/* =============================
 * 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(); });
});

9

仅仅通过更改CSS就无法使其在Chrome上运行,因为我不希望页面滚动回到顶部。这工作正常:

$("#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);
});

1
这是在Bootstrap 3.2上对我有用的唯一解决方案。
volx757 '16

1
角材料侧面导航仪已跃居首位。这是似乎在所有情况下都有效的唯一答案(台式机/移动电话+允许模式/ sidenav中滚动+保持主体滚动位置固定而不跳动)。
cYrixmorten

这也是唯一对我有效的解决方案。tx
Deedz '18

对我
有用

9

试试这个:

.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
    height: 100%;
}

它为我工作。(支持IE8)


4
此方法有效,但也会导致您在使用时打开模态时跳到顶部position: fixed
AlexioVay

8

对于引导,你可以试试这个(在工作FirefoxChromeMicrosoft Edge):

body.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
}

希望这可以帮助...


7

可以添加“ is-modal-open”类或使用javascript修改body标签的样式,并且可以按预期工作。但是我们要面对的问题是当身体溢出时,它会隐藏到顶部(scrollTop将变为0)。稍后将成为可用性问题。

作为此问题的解决方案,而不是更改body标签溢出:隐藏在html标签上进行更改

$('#myModal').on('shown.bs.modal', function () {
  $('html').css('overflow','hidden');
}).on('hidden.bs.modal', function() {
  $('html').css('overflow','auto');
});

1
这绝对是正确的答案,因为一般的共识答案会将页面滚动到顶部,这真是糟糕的用户体验。您应该为此写博客。我最终将其转变为全球解决方案。
史密斯,

这不适用于iPhone。
BadriNarayanan Sridharan

6

我不确定这段代码,但是值得一试。

在jQuery中:

$(document).ready(function() {
    $(/* Put in your "onModalDisplay" here */)./* whatever */(function() {
        $("#Modal").css("overflow", "hidden");
    });
});

就像我之前说的,我不确定100%可以尝试。


1
这并不能阻止人体在打开模式时滚动
xorinzor 2012年

您在charlietfl的答案的评论部分中表示,@ xorinzor可以奏效。但是您说过:这并不能防止在打开模态时主体滚动。
阿尼斯·古普塔

是的,但目前它是部分可行的唯一解决方案,我很好。我之所以将他的回答标记为答案,是因为他早就知道了答案。
xorinzor 2012年

@xorinzor真的,我以为我在他/她之前回答了,可能是一些奇怪的小故障。不过很好
Anish Gupta 2012年


4

最好的解决方案是body{overflow:hidden}大多数答案使用的仅css 解决方案。一些答案提供了一种解决方案,还可以防止滚动条消失引起的“跳转”。但是,没有一个太优雅了。因此,我编写了这两个函数,它们似乎工作得很好。

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');
}

查看此jsFiddle以查看其使用情况。


这不是很老,但是对我来说这些都不起作用,即使是我仍然可以滚动窗口的小提琴,我还缺少什么?
2014年

几次打开和关闭模态,主绿色DIV会不断缩小!
Webinan 2014年

@Webinan我在Win7的Chrome中没有看到此消息。您的浏览器和视口大小是多少?
Stephen M. Harris

1
@smhmic在大约20次打开和关闭后,绿色div的宽度等于open modal按钮的宽度。Chrome on 8
Webinan 2014年

类似于@jpap的答案(stackoverflow.com/a/16451821/5516499),但带有一些错误。:-(
Kivi Shapiro

4

许多人建议在主体上显示“溢出:隐藏”,这将无法工作(至少在我的情况下如此),因为它将使网站滚动到顶部。

这是使用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');
    });

这将使模式的滚动起作用,并阻止网站同时滚动。


看起来此解决方案也修复了此iOS错误:hackernoon.com/…–
Gotenks

3

您可以使用以下逻辑,我对其进行了测试并且可以正常工作(即使在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>

2

我不是100%确信它可以与Bootstrap一起使用,但值得一试-它与Remodal.js一起使用,可以在github上找到:http ://vodkabears.github.io/remodal/,这对于方法是有意义的非常相似。

要阻止页面跳到顶部并防止内容的右移,请body在触发模式时将类添加到,并设置以下CSS规则:

body.with-modal {
    position: static;
    height: auto;
    overflow-y: hidden;
}

position:staticheight:auto结合在一起才能阻止内容向右跳。在overflow-y:hidden;被模态的背后滚动停止页面。


对于Safari 11.1.1,Chrome 67.0.3396.99和Firefox 60.0.2,该解决方案非常适合我。谢谢!
Dom,

2

基于此提琴:http : //jsfiddle.net/dh834zgw/1/

以下代码段(使用jquery)将禁用窗口滚动:

 var curScrollTop = $(window).scrollTop();
 $('html').toggleClass('noscroll').css('top', '-' + curScrollTop + 'px');

并在您的CSS中:

html.noscroll{
    position: fixed;
    width: 100%;
    top:0;
    left: 0;
    height: 100%;
    overflow-y: scroll !important;
    z-index: 10;
 }

现在,当您删除模态时,不要忘记删除html标签上的noscroll类:

$('html').toggleClass('noscroll');

不应overflow设置为hidden吗?+1,因为这对我有用(使用hidden)。
mhulse

2

我有一个由复选框黑客生成的边栏。但是主要思想是保存文档scrollTop,而不是在滚动窗口期间对其进行更改。

我只是不喜欢当正文变为“溢出:隐藏”时页面跳动。

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);
            }
        });
    })

});


2

遗憾的是,以上所有答案都无法解决我的问题。

就我而言,该网页最初具有滚动条。每当我单击模式时,滚动条都不会消失并且标题将向右移动一点。

然后,我尝试添加.modal-open{overflow:auto;}(大多数人推荐)。它确实解决了问题:打开模态后出现滚动条。但是,出现了另一个副作用,即“标题下方的背景将向左移一点,同时模态后面还有另一个长条”

模态后面的长条

幸运的是,添加完后{padding-right: 0 !important;},一切都已完美修复。页眉和正文背景均未移动,并且模式仍保留滚动条。

固定图片

希望这可以帮助仍然坚持该问题的人。祝好运!


1

大部分内容都在这里,但我看不到任何答案可以将所有内容组合在一起。

问题是三重的。

(1)防止基础页面滚动

$('body').css('overflow', 'hidden')

(2)并移除滚动条

var handler = function (e) { e.preventDefault() }
$('.modal').bind('mousewheel touchmove', handler)

(3)清理模态时清理

$('.modal').unbind('mousewheel touchmove', handler)
$('body').css('overflow', '')

如果模式不是全屏模式,则将.modal绑定应用于全屏覆盖。


4
这也防止在模态内滚动。
丹尼尔(Daniel)

同样的问题。您找到解决方案了吗?@Daniel
AlexioVay

@Vay之类的。看看这个:blog.christoffer.me/…–
丹尼尔(Daniel)

1

我对Bootstrap 3的解决方案:

.modal {
  overflow-y: hidden;
}
body.modal-open {
  margin-right: 0;
}

因为对我来说唯一overflow: hiddenbody.modal-open类并没有阻止该网页向左移动由于原来的margin-right: 15px


1

我只是这样做的...

$('body').css('overflow', 'hidden');

但是当滚动条消失时,它向右移动了20px,所以我添加了

$('body').css('margin-right', '20px');

之后。

为我工作。


仅当模态小于屏幕尺寸时,此方法才有效。
谢尔盖(Sergey)

1

如果模式是高度/宽度的100%,“ mouseenter / leave”将起作用以轻松启用/禁用滚动。这对我来说真的很有效:

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); 
});

1

为我工作

$('#myModal').on({'mousewheel': function(e) 
    {
    if (e.target.id == 'el') return;
    e.preventDefault();
    e.stopPropagation();
   }
});

1

为什么不像布尔玛那样去做呢?当模式激活时,将其类.is-clipped添加到html中,这是溢出的:hidden!important; 就是这样。

编辑:Okey,布尔玛有此错误,所以您还必须添加其他内容,例如

html.is-modal-active {
  overflow: hidden !important;
  position: fixed;
  width: 100%; 
}

1

因为对我来说,这个问题主要在iOS上提出,所以我提供了仅在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;
    });
  }

1

上面的答案都不适合我。因此,我发现了另一种有效的方法。

只需添加一个scroll.(namespace)侦听器并将其设置scrollTopdocument最新值即可...

并在关闭脚本中删除侦听器。

// 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');

});

更新

看来,这在chrome上效果不佳。有什么建议可以解决吗?


0

这为我工作:

$("#mymodal").mouseenter(function(){
   $("body").css("overflow", "hidden"); 
}).mouseleave(function(){
   $("body").css("overflow", "visible");
});

0

对于那些想知道如何获取bootstrap 3模态的滚动事件的人:

$(".modal").scroll(function() {
    console.log("scrolling!);
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.