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