仅当模式打开 IOS 时如何禁用正文滚动

Posted

技术标签:

【中文标题】仅当模式打开 IOS 时如何禁用正文滚动【英文标题】:How to disable body scrolling when modal is open IOS only 【发布时间】:2019-07-14 04:13:43 【问题描述】:

仅限ios / iPhone X / iPhone 7等

即使是 jquery 模态库也不起作用! https://jquerymodal.com/ - 在 iPhone 上打开模态框,您将能够滚动正文。

我发现很难找到一种解决方案,可以在每次打开模式时停止正文滚动而不使页面跳转到顶部(这与页面滚动一样糟糕)

这似乎是一个很多人都遇到过的大问题。正如你在这里看到的:

How to prevent body scrolling on iOS 12 when modal opened? https://***.com/questions/49760984/stopping-body-scroll-on-modal-open-bootstrap-4

我在网上搜寻了没有运气,有人有解决办法吗?!

【问题讨论】:

【参考方案1】:

经过多次尝试,我想出了:

/* Default (phone) */
body.modal-open 
    left: 0;
    position: fixed;
    right: 0;
    /* Prevent scrolling of body */
    overflow-y: hidden !important;


/* Small and above e.g. not a phone */
@media (min-width: 576px) 
    body.modal-open 
        /* Keep scrollbar */
        overflow-y: scroll !important;
    

在默认模式(电话)下,我只是删除了垂直滚动条。由于它在手机上,它位于顶部,并且没有宽度。没有overflow-y,手机无法滚动。

但在桌面上,我喜欢永久的水平滚动,所以我在模态时强制打开它以防止屏幕移动 17px 宽度。

如果在桌面(全宽滚动条)上,如果用户将浏览器缩小到小于 576 像素,你会得到一个转变,但我可以忍受。

另外——我允许在模式中滚动。这样,模态不会在移动设备上从屏幕底部跑出。

【讨论】:

【参考方案2】:

export default class BackgroundScroll 
  private scrollPosition = 0;
  disable = (isDisable) => 
    if (isDisable) 
      this.scrollPosition = window.pageYOffset;
      document.body.classList.add('block-body-scroll');
      document.body.style.top = `-$this.scrollPositionpx`;
      if (this.checkIos()) 
        document.body.classList.add('ios');
      
     else 
      document.body.classList.remove('block-body-scroll');
      window.scrollTo(0, this.scrollPosition);
    
  ;

  private checkIos(): boolean 
    return (
      ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(
        navigator.platform
      ) ||
      (navigator.userAgent.includes('Mac') && 'ontouchend' in document)
    );
  
body.block-body-scroll 
  overflow: hidden;
  width: 100%;
  &.ios 
    position: fixed;
  

我们只为 ios 处理 position: fixed。因为position: fixed会影响其他浏览器如火狐。这是我在 typescript 上处理的代码,但纯 JS 或其他任何东西与我的基本相同。

【讨论】:

【参考方案3】:

我创建了以下解决方案,适用于 iOS 12!

虽然下面的嵌入式演示使用的是 Bootstrap 4,但同样的解决方案也适用于 Bootstrap 3,因为所有模式类或事件名称都不同。

第 1 步:在模态打开时使用固定定位将body 冻结到位

当一个 Bootstrap 模态打开时,一个名为 .modal-open 的类被添加到 body 中。将以下附加样式添加到此类:

body 
    &.modal-open 
        bottom: 0;
        left: 0;
        position: fixed;
        right: 0;
        top: 0;
    

现在,每当打开模式时,body 将固定在适当的位置,并调整为与视口本身相同的尺寸。这完全阻止了滚动,因为没有任何地方可以滚动!

但是:这也意味着打开模态框会导致页面跳转到顶部,因为body 不再超出视口的底部边缘(假设页面内容更高)。

第 2 步:在模态打开时模拟之前的滚动距离

Bootstrap 公开在打开或关闭模式时触发的事件。我们可以使用这些来解决“跳到顶部”的问题,方法是在打开模式时拉动body up 的顶部,这样看起来滚动位置没有改变:

$(function() 
    var $window = $(window),
        $body = $("body"),
        $modal = $(".modal"),
        scrollDistance = 0;

    $modal.on("show.bs.modal", function() 
        // Get the scroll distance at the time the modal was opened
        scrollDistance = $window.scrollTop();

        // Pull the top of the body up by that amount
        $body.css("top", scrollDistance * -1);
    );
);

但是,当模态框关闭时页面仍然会跳转到顶部,因为windowscrollTop值仍然是0

第 3 步:关闭模式时重置所有内容

现在我们只需要挂钩在模式关闭时触发的事件,并将所有内容恢复原状:

移除body上的固定定位和负上限值 将窗口的滚动位置设置回原来的位置
$modal.on("hidden.bs.modal", function() 
    // Remove the negative top value on the body
    $body.css("top", "");

    // Set the window's scroll position back to what it was before the modal was opened
    $window.scrollTop(scrollDistance);  
);

无需手动移除body 上的固定定位,因为这是通过.modal-open 类设置的,Bootstrap 会在模态关闭时移除该类。


演示

将它们放在一起,现在您可以在模式打开时阻止 iOS 上的背景滚动,而不会丢失滚动位置!

在 iOS 设备上打开以下链接:https://daguy.github.io/ios-modal-fix/

【讨论】:

我已经在我的 iPhone 上用这个 codepen 尝试过这个代码:codepen.io/bkdigital/pen/YBbpvN - 它似乎不起作用,请在你的 iPhone 设备上尝试一下?您只能看到页面顶部,无论模态是否打开,正文都会被切断。 您有使用过此解决方案的网站吗? @daGuy @BennKingy – 看起来 Codepen 本身以某种方式干扰了它。它在我在独立页面上运行 iOS 12 的 iPhone XR 上完美运行:daguy.github.io/ios-modal-fix 在页面的顶部和底部都有打开模态的按钮,这样你就可以看到它在不同的滚动位置是如何工作的。 我已经在那里测试了你的链接并且它的工作完美!血腥的代码笔:P 我今天将实现这个 TYVM!【参考方案4】:

嗯,我看到关于 SO 的主题很少。 试试这个吧?

@supports (-webkit-overflow-scrolling: touch) 
  /* CSS specific to iOS devices */ 


@supports not (-webkit-overflow-scrolling: touch) 
  /* CSS for other than iOS devices */ 

CSS media query target only iOS devices

【讨论】:

我不需要 IOS 特定的样式 hack,我需要在 IOS 上打开模式时停止正文滚动。

以上是关于仅当模式打开 IOS 时如何禁用正文滚动的主要内容,如果未能解决你的问题,请参考以下文章

css 打开模态上的bootstrap,禁用正文滚动

css 打开模式对话框窗口时禁用Body上的滚动

加载 twitter 引导模式对话框时,如何防止正文滚动条和移位?

Ipad iOS 滚动不一致:禁用正文滚动但允许在某些元素上滚动

如何在不隐藏正文滚动条的情况下在固定 div 上滚动时禁用正文滚动?

如何禁用滚动文档正文?