iOS Safari/Chrome - 在模式内聚焦输入时不需要的滚动
Posted
技术标签:
【中文标题】iOS Safari/Chrome - 在模式内聚焦输入时不需要的滚动【英文标题】:iOS Safari/Chrome - Unwanted scrolling when focusing an input inside the modal 【发布时间】:2016-09-14 04:54:23 【问题描述】:在 Safari 和 Chrome 中测试 - 结果相同,所以我认为这是 ios 问题。
仅当模态框内有输入并且我点击该输入时才会发生这种情况。在输入获得焦点的同一时刻,原生 iOS 键盘变得可见。
模态下方的页面在同一时刻自动滚动到其高度的 50%。这种行为是完全不受欢迎的,我不知道如何阻止这个默认的 iOS“功能”。
演示:
【问题讨论】:
使用 DOMListener for Chrome 获取 DOM 更改日志。我在打开模式和添加 1 种媒体查询样式时进行了 59 处更改。还要检查调整大小处理程序。位置固定或溢出隐藏也可能是问题。 感谢@Pinal 的回复!我尝试将overflow: hidden
动态添加到正文中,但在这种情况下没有帮助。可能position: fixed
是问题所在。您能否详细解释一下为什么会出现问题以及如何解决。
刚刚注意到position:fixed
在iOS CoreGraphics 渲染中存在一些问题。在您的情况下,我建议您将所有 position: fixed
更改为绝对值并再次测试。您也可以在 github 上寻找解决方案(例如 - github.com/scottjehl/Device-Bugs/…)
我注意到这个函数 close(i, expectedNumberOfNonCommentArgs) 会影响这个东西,当你尝试评论它时,Safari 中没有 bg 滚动。
【参考方案1】:
只需在此处添加答案,以防人们偶然发现此问题 (rather than your other question, which has a great demo to illustrate this issue)
我们在工作中也面临着类似的问题。正如您所提到的,偏移量始终约为页面高度的 50%,无论您的初始偏移量在哪里,都会发生这种情况。
在过去,当我观察到与早期 iOS 版本类似的“跳跃”(尽管没有那么剧烈的跳跃)时,我通常通过将position: fixed
(或relative
)应用于body
来解决这个问题(which allows overflow: hidden
to properly work)。
但是,如果用户向下滚动,这会导致用户自动返回页面顶部。
所以,如果您愿意通过 javascript
来解决这个问题,这里是我整理的修复/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
对于那些正在寻找更通用修复的人,您可以在打开/关闭模式时执行以下操作:
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)
,在IE中通过window.pageYOffset
获取scrollTop【参考方案2】:
我也遇到过这个问题。一个简短的解释是,iOS Safari 将尝试自动滚动到任何聚焦的输入,在这种特殊情况下,聚焦元素位于固定定位的元素内。当 Safari 想要使元素在屏幕上居中因此背景滚动时,它似乎很难找到固定位置的元素。
一种可能的解决方法是将touchstart
事件侦听器添加到输入字段并计算叠加层的当前位置,将定位更改为绝对位置并更新顶部/左侧位置以将叠加层放回原来的位置固定位置时的屏幕,最后添加一个新的blur
侦听器,以在输入焦点/模糊时将覆盖重置回固定位置。这应该可以防止页面滚动。我建议使用touchstart
,因为它应该在focus
事件之前触发,在这种情况下页面已经开始滚动。触发focus
事件时,Safari 应该能够找到绝对定位的叠加层并将其居中。
【讨论】:
【参考方案3】:所以我已经解决了这个问题并在我的 Iphone 5 上进行了测试,没有 Ipad 可以检查。
我在我的解决方案中禁用了overflow:hidden
,您可以添加,如果您想对所有模式禁用全部滚动。
解决方案是向 html 和 body 元素添加基本的 height 和 position 属性。
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);
在 IOS 9.3.2 上测试的上述 js 解决方案对我来说就像魅力一样]
【讨论】:
【参考方案4】:为了阻止页面在 x 和 y 轴上滚动,我们在 css 中使用overflow: hidden;
属性。
所以如果我们把它应用到身体上,
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()">Click Me!</button>
除此之外,我们必须将其添加到 css 文件中。
body
overflow: initial !important;
body.modal-active
overflow: hidden !important;
我们去吧。
【讨论】:
【参考方案5】:我不是 100% 确定,但我可以想象以下情况:
当键盘出现时,窗口高度减小,但scrollTop值还是一样,所以网站跳转到那个值。当模式打开时,您可以将overflow:hidden
添加到body
。这将阻止模式“背后”的滚动,并可能解决您的问题。
【讨论】:
感谢@Kilian 的回复!不幸的是,这个技巧并不能解决我的问题。除此之外,当我将overflow: hidden
添加到正文时,在桌面浏览器中会出现此负面影响i.imgur.com/HDOxzmm.gif(正文在滚动条显示/隐藏时左右移动)。
嗯,您可以将 overflow
添加到 #wrapper
而不是 body
以避免该问题。然后,将position:absolute
添加到模态而不是fixed
。你已经试过了吗?但是,如果您添加 position:absolute
而不添加 overflow:hidden
,则打开模式时页面将跳转到顶部。【参考方案6】:
我尝试了多种方法,这些方法适用于 html 页面上的弹跳模式输入。对我有用的最简单的解决方案是在页面上打开模式时向 body 标签添加以下样式。
position: fixed;
width: 100%;
【讨论】:
【参考方案7】:添加此元 (maximum-scale=1, minimum-scale=1 ) 以重置滚动,这是在聚焦输入字段时发生的。
【讨论】:
【参考方案8】:我在升级到 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 版本的检测,并且只为低于该版本的版本运行脚本。
【讨论】:
以上是关于iOS Safari/Chrome - 在模式内聚焦输入时不需要的滚动的主要内容,如果未能解决你的问题,请参考以下文章
移动 iOS 和 Android Safari/Chrome 之间的 JavaScript 差异
在 iOS 13 safari/chrome 浏览器中播放音频 (mp3) 的延迟
iOS Safari/Chrome 不会向上滚动以在无线电输入上显示验证错误消息