iOS Safari/Chrome - 在模态框内聚焦输入框时出现意外滚动

33

在Safari和Chrome中测试-结果相同,所以我认为这是iOS的问题。

仅当模态框内有输入并且我点击该输入时才会发生此情况。 在同一时刻,该输入获得焦点并且原生的iOS键盘变得可见。

模态框下面的页面同时自动滚动到其高度的50%。这种行为完全不受欢迎,我不知道如何防止这种默认的iOS“功能”。

演示:

输入图像描述


使用DOMListener来获取Chrome的DOM更改日志。打开模态框并添加一个媒体查询样式后,我得到了59个更改。还要检查resize处理程序,position fixed或overflow hidden也可能是问题。 - Alex
感谢@Pinal的回复!我尝试动态添加overflow: hidden到body,但在这种情况下它没有帮助。可能是position: fixed引起的问题。您能否详细解释一下为什么会出现问题以及如何解决呢? - Limon Monte
1
刚刚注意到在iOS CoreGraphics渲染中,position:fixed存在一些问题。建议您将所有的position: fixed更改为absolute并重新测试。此外,您还可以在github上寻找解决方案(例如:https://github.com/scottjehl/Device-Bugs/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen++fixed++ios+)。 - Alex
我注意到这个函数close(i, expectedNumberOfNonCommentArgs)会影响到某些东西,当你试图注释它时,在Safari中没有背景滚动。 - GL.awog
8个回答

12

如果有人偶然遇到这个问题(而不是你的另一个问题,该问题有很好的演示来说明此问题),我在此添加了答案。

我们在工作中遇到了类似的问题。正如您所提到的,无论初始偏移量在哪里,偏移量始终为页面高度的约50%。

过去,在早期的iOS版本中,当我观察到类似的“跳跃”现象时(尽管跳跃幅度小得多),我通常通过将position:fixed(或relative)应用于body这允许overflow:hidden正常工作)来解决这个问题。

然而,这会带来一个意想不到的后果,即如果用户向下滚动,则会将其跳回页面顶部。

因此,如果您愿意使用一些JavaScript来解决此问题,以下是我准备的修复/黑客方法:

// Tapping into swal events
onOpen: function () {
  var offset = document.body.scrollTop;
  document.body.style.top = (offset * -1) + 'px';
  document.body.classList.add('modal--opened');
},
onClose: function () {
  var offset = parseInt(document.body.style.top, 10);
  document.body.classList.remove('modal--opened');
  document.body.scrollTop = (offset * -1);
}

而CSS的外观如下:

.modal--opened {
  position: fixed;
  left: 0;
  right: 0;
}

这是你之前提出的另一个问题中的演示页面的分支,以说明问题:https://jpattishall.github.io/sweetalert2/ios-bug.html

对于那些寻找更一般性解决方案的人,当打开/关闭模态框时,可以执行以下操作:

function toggleModal() {
    var offset;
    if (document.body.classList.contains('modal--opened')) {
        offset = parseInt(document.body.style.top, 10);
        document.body.classList.remove('modal--opened');
        document.body.scrollTop = (offset * -1);
    } else {
        offset = document.body.scrollTop;
        document.body.style.top = (offset * -1) + 'px';
        document.body.classList.add('modal--opened');
    }
}

编辑:为了避免在桌面上出现“移动/不移动”的情况,建议使用功能检测/ua嗅探,仅将其应用于移动Safari。

在IE中,仅供参考,document.body.scrollTop始终为0,设置它不会滚动。请改用window.scroll(x,y),并通过window.pageYOffset获取IE中的scrollTop。 - Jeremy Bernier

1
我也遇到了这个问题。简单来说,iOS Safari会尝试自动滚动到任何被聚焦的输入框,而在这种情况下,聚焦的元素位于固定定位的元素内部。Safari似乎很难找到要居中显示在屏幕上的固定位置元素,因此会出现背景滚动的情况。
一个可能的解决方法是为输入字段添加一个touchstart事件监听器,并计算覆盖层的当前位置,将其定位更改为绝对定位,并更新顶部/左侧位置以将覆盖层放回固定定位时在屏幕上的位置,最后添加一个新的blur监听器,在离开焦点/模糊输入时将覆盖层重置回固定定位。这应该可以防止页面滚动。建议使用touchstart因为它应该在focus事件之前触发,而此时页面已经开始滚动。当触发focus事件时,Safari应该能够找到并居中显示绝对定位的覆盖层。

1

所以我已经解决了这个问题,并在我的 iPhone 5 上进行了测试,没有 iPad 来检查。 在我的解决方案中,我已经禁用了 overflow:hidden,如果您想要禁用所有模态框的滚动条,可以添加此代码。 解决方案是基本上将高度和位置属性添加到 html 和 body 元素中。

html, body {
   position:relative;
   /*overflow:hidden;*/
   height: 100%;
}

因此,只有当您专注于输入时,高度和位置才会被定义。我已经从您的存储库中编写了此解决方案,并将向您发送拉取请求。

我还在您的gulp设置中添加了browserSync。因此,现在可以轻松测试任何设备。

干杯!

编辑:如果上述解决方案由于某种原因无法正常工作,则可以尝试另一种方法。

 /*
  * @summary touch handler; will remove touch ability
  * @author yeomann
  */
  function Touchyhandler(e) {
    e.preventDefault();
  }

后来可以通过以下方式实现动态添加和删除触摸监听器:

//to add
document.addEventListener('touchmove', Touchyhandler, false); 
//to remove   
document.removeEventListener('touchmove', Touchyhandler);

以上的 JavaScript 解决方案在 iOS 9.3.2 上经过测试,对我非常有效。


1
为了阻止页面在x和y轴上滚动,我们使用CSS中的overflow: hidden;属性。因此,如果我们将此应用于body元素,
body {
    overflow: hidden !important;
}

这应该可以工作,对吧?

实际上,这并不起作用,因为您刚刚禁用了整个页面的x和y滚动。

为了绕过这个问题,我们可以使用一点JavaScript,在模态框处于活动状态时向body添加一个类。

首先,我们必须向body添加一个id:<body id="body">,这样JavaScript才能识别body。

其次,我们必须向模态框添加一个id:<div id="modal">,同样允许JavaScript识别模态框。

<script type="text/javascript">
    function modalActive() {
        if (document.getElementById("modal").classList.contains("active")) {
            document.getElementById("body").classList.add("modal-active");
        } else {
            getElementById("modal").classList.remove("active"));
            getElementById("body").classList.remove("modal-active"));           
        }
    }
</script>

对于启动和关闭模态框的按钮,我们必须添加一个onclick事件。 <button onclick="modalActive()">点击我!</button> 除此之外,我们还必须将其添加到CSS文件中。
body {
    overflow: initial !important;
}

body.modal-active {
    overflow: hidden !important;
}

然后我们开始。


0

我不是100%确定,但我可以想象以下情况:

当键盘出现时,窗口高度会减小,但scrollTop值仍然相同,因此网站会跳转到该值。当模态框打开时,您可以向添加overflow:hidden。这将阻止在模态框“后面”的滚动,并可能解决您的问题。


感谢@Kilian的回复!不幸的是,这个技巧并没有解决我的问题。此外,当我在body中添加overflow: hidden时,在桌面浏览器中会出现负面影响,如下图所示:https://i.imgur.com/HDOxzmm.gif(当滚动条显示/隐藏时,body会左右移动)。 - Limon Monte
嗯,你可以将overflow添加到#wrapper而不是body中,以避免这个问题。然后,将模态框的属性改为position:absolute而不是fixed。你已经尝试过了吗? 但是,如果你在没有添加overflow:hidden的情况下添加position:absolute,当你打开模态框时页面会跳到顶部。 - Kilian So

0

我尝试了多种方法来解决HTML页面上弹跳模态输入的问题。对于我来说,最简单有效的解决方案是在页面上打开模态框时,为body标签添加以下样式

position: fixed;
width: 100%;

0

将此元标记 (maximum-scale=1, minimum-scale=1) 添加到重置滚动条,以解决聚焦输入字段时出现的问题。


0

我在升级到iPadOS 13后遇到了这个问题。我不得不删除以下旧的JavaScript代码,这些代码是为了解决旧版本中的不同滚动问题而需要的:

function fixIpadKeyboardScrolling() {
   if ((Device.is("ipad") || Device.is("iphone"))) {
    console.log("Fixing iPad/iPhone floating bar bug");
    var inputs = document.getElementsByTagName("input");
    if (inputs.length) {
      for (var i = inputs.length - 1; i >= 0; i--) {
        addListener(inputs[i], "blur", function () {
          setTimeout(function () {
              window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
          }, 0);
        });
      }
    }
    console.log(inputs.length + " input controls where edited to fix keyboard scrolling");
  }
}

如果您在升级后突然遇到此问题,则可能已将类似的代码应用于您的应用程序。
在我的情况下,我添加了对Safari移动版13版本的检测,并仅运行低于该版本的脚本。

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