打开模态框时防止页面滚动

432

当我的网站上的模态框(来自http://twitter.github.com/bootstrap)打开时,我希望我的页面停止使用鼠标滚轮进行滚动。

我尝试在打开模态框时调用下面的JavaScript代码,但没有成功。

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

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

请注意,我们的网站已经不再支持IE6浏览器,但需要兼容IE7+。

52个回答

536

Bootstrap 的 modal 在显示模态对话框时自动向 body 添加类 modal-open,当隐藏对话框时则会将其移除。因此,您可以在 CSS 中添加以下内容:

body.modal-open {
    overflow: hidden;
}

你可以认为上面的代码属于Bootstrap CSS代码库,但是将其添加到您的网站中很容易解决。

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

一个解决方法是在模态框即将显示时将该类添加到body中,在模态框关闭时将其删除:

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

2013年3月11日更新 看起来modal-open类将在Bootstrap 3.0中重新出现,专门用于防止滚动:

在body上重新引入.modal-open(这样我们就可以在那里禁用滚动)

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


3
在Bootstrap 2.2.2中,这不再起作用了。希望 ".modal-open" 在将来会回归... https://github.com/twitter/bootstrap/issues/5719 - ppetrid
3
我不期望它会返回。根据这篇文章:https://github.com/twitter/bootstrap/wiki/Upcoming-3.0-changes(看底部)。引用:“不再有内部模态滚动。相反,模态将增长以容纳其内容,并且页面滚动以容纳模态。” - MartinHN
3
@Bagata Cool - “modal-open” 将会在 Bootstrap 3 中恢复,因此当它推出时,应该可以安全地删除上述代码。 - MartinHN
3
如果所选答案不能满足您的需求,那么请继续向下滚动,有可能会发现像这样的珍品。没想到一篇得到97个赞的答案会埋在其他不受欢迎的评论下面。 - Mohd Abdul Mujib
6
问题在于为了防止模态框打开时文档滚动到顶部,您需要添加body.modal-open {overflow: visible}。您的解决方案目前可以使用,但缺点是每次打开模态框时文档都会滚动到顶部。 - patrick
显示剩余17条评论

142

被接受的答案在移动设备上(至少是iOS 7 w/ Safari 7)无法使用,而且我不想在我的网站上运行更多的JavaScript,因为CSS可以解决问题。

这个CSS将防止背景页面在模态框下滚动:

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

然而,它也有一个轻微的副作用,即基本上滚动到顶部。position:absolute可以解决这个问题,但是会重新引入在移动设备上滚动的能力。

如果您知道您的视口(我的添加视口到<body>的插件),您只需为position添加一个CSS切换即可。

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

这个回答是一个跨帖子发布。


9
谢谢!移动端(至少是iOS和Android原生浏览器)让我头疼,如果不在body上添加 position:fixed 样式,它们就无法正常工作。 - Raul Rene
感谢您还包括了防止页面在显示/隐藏模态框时向左/右跳动的代码。这非常有用,我验证了它可以解决我在运行iOS 9.2.1的iPhone 5c上Safari遇到的问题。 - Elijah Lofgren
10
为了解决回到页面顶部的问题,你可以在添加类之前记录位置,然后在删除类后,将窗口滚动到记录的位置。这就是我为自己解决该问题的方式:http://pastebin.com/Vpsz07zd。 - Tool
虽然我觉得这只适用于非常基本的需求,但这是一个有用的修复。谢谢。 - Steve Benner
以下是我使用jQuery保留滚动位置的方法: const currPageScrollPos = $(window).scrollTop() $("body").removeClass("show_overlay") $(window).delay(5).scrollTop(currPageScrollPos) - Aerodynamic

39

只需隐藏body的overflow属性,即可使body不滚动。当您隐藏模态框时,请将其恢复为自动模式。

以下是代码:


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

25

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

打开模态框:

  1. 记录 body 宽度
  2. body 的 overflow 设置为 hidden
  3. 明确将 body 的宽度设置为步骤1中的值。

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

关闭模态框:

  1. body的overflow属性设为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
3
是的,"jumpy"指的是"文档重排"。很高兴能帮到你! :-) - jpap
这个问题有 CSS 的解决方案吗?它在所有浏览器和移动设备上都能工作吗? - Ruben
最后一步应该是 $body.css("overflow", "auto");,只是一个打字错误 :) - schneikai
哇,这主意太棒了。@jpap,你帮我解决了困扰我很长时间的文档重排问题。 - Goran Radulovic

21

当弹出框打开时,您可以尝试将body大小设置为窗口大小,并使用overflow: hidden。


13
这样做会在每次打开模态框时移动屏幕,这并不方便。我只需要禁用背景滚动。 - xorinzor
不确定滚动条是否与浏览器相关,您无法对其进行太多操作。 - charlietfl
9
重点不是阻止模态框的滚动,而是阻止背景中的页面滚动。 - xorinzor
1
它是窗口,如果主体溢出,则滚动。例如,滚动条不是文档的一部分。 - charlietfl
很棒的解决方案;你只需要考虑滚动条,以避免文档重新布局和内容“跳动”。请查看我的答案。 - jpap
显示剩余2条评论

18

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


另一个选项:滚轮事件

scroll事件不可取消。但是可以取消mousewheelwheel事件。但需要注意的是,并非所有的旧浏览器都支持它们,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是一个在线代码编辑器,你可以在这里编写、运行和分享HTML、CSS和JavaScript代码。

你的 JSFiddle 在 Firefox 24、Chrome 24 和 IE9 上都无法正常工作。 - AxeEffect
@AxeEffect现在应该可以工作了。唯一的问题是对Bootstrap库的外部引用已经发生了变化。感谢您的提醒。 - merv
3
这不会阻止触摸设备滚动,现在最好使用overflow:hidden - Positivity
5
他们都在工作,但不支持移动设备。-__- 在Android 4.1和Chrome上测试过。 - Tower Jimmy
@TowerJimmy 你可能需要取消触摸或拖动事件(如果可能的话)。 - xorinzor

11

试试这个:

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

它对我起作用了。(支持IE8)


9
当使用 position: fixed 时,打开模态框会让页面回到顶部,虽然可以正常运行。 - AlexioVay

10

即使到了2020年,caniuse仅支持此功能的比例也只有78%。几乎不是一个可行的解决方案。 - Hybrid web dev
2
2022年看起来会更好:https://caniuse.com/?search=overscroll-behavior - Avatar
1
在桌面端运行良好。我注意到的限制(2022年12月7日)。不适用于桌面端。不适用于非可滚动div(考虑带有overflow-y:auto的div,在任何给定点可能是可滚动或不可滚动的)。 - Llama D'Attore

9

将类'is-modal-open'添加到body标签或使用javascript修改其样式是可以的,它将按预期工作。但我们将面临的问题是当body变为overflow:hidden时,它会跳到顶部(scrollTop将变为0)。这将成为以后的可用性问题。

作为解决此问题的方法,不要更改body标签的overflow:hidden属性,而是更改html标签的属性。

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

1
这绝对是正确的答案,因为普遍共识的答案会将页面滚动到顶部,这是一个可怕的用户体验。你应该写一篇博客来讲述这个问题。我最终将其转化为全局解决方案。 - Smith

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接