iOS Safari/Chrome - 聚焦模态内的输入时不需要的滚动

iOS Safari/Chrome - Unwanted scrolling when focusing an input inside the modal

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

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

模态下方的页面在同一时刻自动滚动到其高度的 50%。这种行为是完全不需要的,我不知道如何防止这种默认 iOS "feature".

演示:

我不是 100% 确定,但我可以想象以下内容:

当键盘出现时,window 高度降低,但 scrollTop 值仍然相同,因此站点跳转到该值。当模式打开时,您可以将 overflow:hidden 添加到 body。这将阻止滚动 "behind" 模式并可能解决您的问题。

我也遇到过这个问题。一个简短的解释是 iOS Safari 将尝试自动滚动到任何聚焦的输入,在这种特殊情况下,聚焦元素位于固定定位元素内。当 Safari 想要在屏幕上居中放置元素时,Safari 似乎很难找到固定位置的元素,因此背景会滚动。

一种可能的修复方法是向输入字段添加一个 touchstart 事件侦听器并计算叠加层的当前位置,将定位更改为绝对定位并更新 top/left 位置以放置叠加层回到固定位置时它在屏幕上的位置,最后添加一个新的 blur 侦听器以在将 focus/blurring 留在输入上时将叠加层重置回固定位置。这应该可以防止页面滚动。我建议使用 touchstart 因为它应该在 focus 事件之前触发,在这种情况下页面已经开始滚动。当触发 focus 事件时,Safari 应该能够找到并居中绝对定位的覆盖。

所以我已经解决了这个问题并在我的 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);

以上 js 解决方案在 IOS 9.3.2 上测试对我来说很有魅力]

要停止页面在 x 轴和 y 轴上滚动,我们使用 css 中的 overflow: hidden; 属性。

因此,如果我们将其应用于 body,

body {
    overflow: hidden !important;
}

应该可以吧?

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

为了绕过这个,我们可以使用一点 javascript 在模态处于活动状态时将 class 添加到 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()">Click Me!</button>

最重要的是,我们必须将其添加到 css 文件中。

body {
    overflow: initial !important;
}

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

我们开始了。

只是在这里添加一个答案,以防人们偶然发现这个问题 ()

我们在工作中遇到了类似的问题。正如您所提到的,偏移量始终是页面高度的 ~50%,无论您的初始偏移量在哪里,都会发生这种情况。

过去,当我观察到早期 iOS 版本有类似的“跳跃”(尽管跳跃不那么剧烈)时,我通常会通过应用 position: fixed(或 relative) 到 body (which allows overflow: hidden to properly work).

但是,如果用户向下滚动,这会产生意想不到的后果,即让用户返回页面顶部。

所以,如果您愿意与一些 JavaScript 一起解决这个问题,这里是我整理的 fix/hack:

// 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

对于那些正在寻找更通用的修复方法的人,您可以在 opening/closing 模态时执行以下操作:

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

编辑:为了避免桌面上的“shifting/unshifting”,我建议功能 detection/ua 嗅探以仅将其应用于移动 safari。

我尝试了多种方法,这些方法对 html 页面上的弹跳模态输入有效。对我有用的最简单的解决方案是在页面上打开 模式时向 body 标记添加以下样式。

position: fixed;
width: 100%;

添加此元数据(maximum-scale=1, minimum-scale=1 )以重置在输入字段聚焦时发生的滚动。

我在升级到 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 mobile 13 版本的检测,并且仅 运行 低于该版本的脚本。