Javascript iOS Safari/Chrome - 在模态内聚焦输入时不需要滚动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37287148/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS Safari/Chrome - Unwanted scrolling when focusing an input inside the modal
提问by Limon Monte
Tested in Safari and Chrome - the same result, so I think it's iOS issue.
在 Safari 和 Chrome 中测试 - 结果相同,所以我认为这是 iOS 问题。
This happens only if there's an input inside the modal and I tap that input. In the same moment that input got focus and native iOS keyboard become visible.
仅当模态中有输入并且我点击该输入时才会发生这种情况。在输入获得焦点的同时,原生 iOS 键盘变得可见。
Page below modal in the same moment is automatically scrolled to 50% of its height. This behaviour is totally unwanted and I have no clue how to prevent this default iOS "feature".
同一时刻模态下方的页面会自动滚动到其高度的 50%。这种行为是完全不需要的,我不知道如何阻止这个默认的 iOS“功能”。
Demo:
演示:
采纳答案by Hyman
Just adding an answer here in case people stumble upon this question (rather than your other question, which has a great demo to illustrate this issue)
只是在这里添加一个答案,以防人们偶然发现这个问题(而不是你的另一个问题,它有一个很好的演示来说明这个问题)
We are facing a similar issue at work. As you mentioned, the offset is always ~50% of the height of the page, which happens regardless of where your initial offset is.
我们在工作中也面临着类似的问题。正如您所提到的,偏移量始终是页面高度的 50%,无论您的初始偏移量在哪里,都会发生这种情况。
In the past, when I observed a similar "jumping" with earlier iOS versions (albeit, much less dramatic jumping), I have usually worked around this by applying position: fixed
(or relative
) to the body
(which allows overflow: hidden
to properly work).
过去,当我观察到与早期 iOS 版本类似的“跳跃”(尽管跳跃不那么剧烈)时,我通常通过将position: fixed
(或relative
) 应用到body
(这允许overflow: hidden
正常工作)来解决这个问题。
However, this has the unattended consequence of jumping the user back to the top of the page, if they've scrolled down.
但是,如果用户向下滚动,这会导致用户跳回页面顶部的无人值守后果。
So, if you're open to addressing this issue with some JavaScript
, here's a fix/hack I've thrown together:
所以,如果你愿意用 some 来解决这个问题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);
}
And what the CSS looks like:
以及 CSS 的样子:
.modal--opened {
position: fixed;
left: 0;
right: 0;
}
Here's a fork of your demo page (from your other question), to illustrate: https://jpattishall.github.io/sweetalert2/ios-bug.html
这是您的演示页面的一个分支(来自您的其他问题),以说明:https: //jpattishall.github.io/sweetalert2/ios-bug.html
And for those who are looking for a more general fix, you could do something like the following when opening/closing a modal:
对于那些正在寻找更通用修复的人,您可以在打开/关闭模态时执行以下操作:
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');
}
}
Edit: To avoid the "shifting/unshifting" on desktops, I would suggest feature detection/ua sniffing to apply this to only mobile safari.
编辑:为了避免台式机上的“移动/取消移动”,我建议功能检测/ ua 嗅探将其仅应用于移动 safari。
回答by DKrautkramer
I have experienced this issue as well. A short explanation is that iOS Safari will try to auto scroll to any input that is focused on and in this particular case the focused element is within a fixed positioned element. Safari seems to struggle with finding the fixed position element when it wants to center the element on the screen hence the background scrolling.
我也遇到过这个问题。一个简短的解释是,iOS Safari 将尝试自动滚动到任何聚焦的输入,在这种特殊情况下,聚焦元素位于固定定位的元素内。当 Safari 想要将元素在屏幕上居中时,它似乎很难找到固定位置元素,从而导致背景滚动。
One possible fix is to add a touchstart
event listener to the input field and calculate the current position of the overlay, change the positioning to absolute and update the top/left position to place the overlay back where it was on the screen when fixed positioned, and finally add a new blur
listener to reset the overlay back to fixed positioning when leaving focus/blurring on the input. This should prevent the page from scrolling. I suggest using touchstart
because it should trigger before the focus
event at which case the page will already start scrolling. Safari should be able to find and center the absolute positioned overlay when the focus
event is triggered.
一种可能的解决方法是touchstart
在输入字段中添加一个事件侦听器并计算叠加层的当前位置,将定位更改为绝对位置并更新顶部/左侧位置以在固定定位时将叠加层放回屏幕上的位置,以及最后添加一个新的blur
侦听器以在输入上留下焦点/模糊时将覆盖重置回固定位置。这应该可以防止页面滚动。我建议使用,touchstart
因为它应该在focus
事件发生之前触发,在这种情况下页面已经开始滚动。Safari 应该能够在focus
触发事件时找到绝对定位的叠加层并将其居中。
回答by Danish
So i have solved this and tested on my Iphone 5, don't have Ipad to check.
I have disable overflow:hidden
in my solution, you can add, If you want to disable scroll all in one for all modals.
Solution is to add basically height and position property to both html and body element.
所以我已经解决了这个问题并在我的 Iphone 5 上进行了测试,没有 Ipad 来检查。我overflow:hidden
在我的解决方案中禁用了,你可以添加,如果你想禁用所有模式的全部滚动。解决方案是向 html 和 body 元素添加基本的 height 和 position 属性。
html, body {
position:relative;
/*overflow:hidden;*/
height: 100%;
}
So, that only when you focus on input, height and position will be defined, i have already coded this solution from your repo, i will send you a pull request. I have also added browserSync in your gulp setup. Therefore, Now it will be easy to test across any device.
所以,只有当你专注于输入时,高度和位置才会被定义,我已经从你的仓库中编写了这个解决方案,我会向你发送拉取请求。我还在你的 gulp 设置中添加了 browserSync。因此,现在可以轻松地在任何设备上进行测试。
Cheers!
干杯!
EDIT: another way, if above solution don't work for some reason. then,
编辑:另一种方式,如果上述解决方案由于某种原因不起作用。然后,
/*
* @summary touch handler; will remove touch ability
* @author yeomann
*/
function Touchyhandler(e) {
e.preventDefault();
}
and later pragmatically add and remove touch listener like this
然后务实地添加和删除这样的触摸监听器
//to add
document.addEventListener('touchmove', Touchyhandler, false);
//to remove
document.removeEventListener('touchmove', Touchyhandler);
above js solution tested on IOS 9.3.2 work like charm for me]
以上在 IOS 9.3.2 上测试的 js 解决方案对我来说就像魅力一样]
回答by harryparkdotio
To stop the page from scrolling, in both x, and y axis, we use the overflow: hidden;
attribute in css.
为了阻止页面在 x 轴和 y 轴上滚动,我们使用了overflow: hidden;
css 中的属性。
So if we apply this to the body,
所以如果我们把这个应用到身体上
body {
overflow: hidden !important;
}
It should work right?
它应该正常工作吗?
In fact, this actually doesn't work, because you've just disabled x and y scrolling for the entire page the for the entire time.
事实上,这实际上是行不通的,因为您只是一直禁用整个页面的 x 和 y 滚动。
To bypass this, we can use a tad a javascript to add a class to the body when the modal is active.
为了绕过这个,我们可以在模态处于活动状态时使用一点 javascript 向主体添加一个类。
First we must add an id to our body, <body id="body">
this allows javascript to recognize the body.
首先我们必须为我们的身体添加一个 id,<body id="body">
这允许 javascript 识别身体。
Secondly, we must add an id to our modal, <div id="modal">
, also allowing javascript to recognize the modal.
其次,我们必须为我们的模态添加一个 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>
for both the button that launches, and closes the modal, we must add an onclick event,
对于启动和关闭模式的按钮,我们必须添加一个 onclick 事件,
<button onclick="modalActive()">Click Me!</button>
<button onclick="modalActive()">Click Me!</button>
On top of that we must add this to the css file.
最重要的是,我们必须将其添加到 css 文件中。
body {
overflow: initial !important;
}
body.modal-active {
overflow: hidden !important;
}
And there we go.
我们走了。
回答by Kilian So
I'm not 100% sure but i could imagine the following:
我不是 100% 确定,但我可以想象以下内容:
When the keyboard appears, the window height decreases, but the scrollTop value is still the same, so the site jumps to that value. You could add overflow:hidden
to the body
when the modal is open. This will block the scrolling "behind" the modal and probably solve your problem.
当键盘出现时,窗口高度降低,但是scrollTop值还是一样,所以站点跳转到那个值。您可以在模态打开时添加overflow:hidden
到body
。这将阻止在模态“后面”滚动并可能解决您的问题。
回答by Manohar Mankala
I tried multiple things which kind of worked for the bouncing modal inputs on the html page. The simplest solution which worked for me was adding following styles to the body tag when the modal is openon the page.
我尝试了多种方法,这些方法适用于 html 页面上的弹跳模式输入。对我有用的最简单的解决方案是在页面上打开模态时向body 标记添加以下样式。
position: fixed;
width: 100%;
回答by Pranav K
Add this meta (maximum-scale=1, minimum-scale=1) to reset the scroll, which occurred when focusing the input field.
添加此元 ( maximum-scale=1, minimum-scale=1) 以重置滚动,这是在聚焦输入字段时发生的。
回答by Sebris87
I had this issue after upgrading to iPadOS 13. I had to remove the following old JavaScript code, which was required to fix a different scrolling issue in older versions:
升级到 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");
}
}
If you are suddenly experiencing this issue after upgrading you may have similar code applied to your application.
如果您在升级后突然遇到此问题,您的应用程序可能应用了类似的代码。
In my case I added detection for version safari mobile 13 and only run the script for versions less than that.
就我而言,我添加了对 safari mobile 13 版本的检测,并且只运行低于该版本的脚本。