iOS 5 固定定位和虚拟键盘
我有一个移动网站,它有一个 div 通过位置固定在屏幕底部:固定。在 iOS 5 中一切正常(我正在 iPod Touch 上进行测试),直到我进入带有表单的页面。当我点击输入字段并出现虚拟键盘时,我的 div 的固定位置突然丢失了。现在,只要键盘可见,div 就会随页面滚动。一旦我单击完成关闭键盘,div 就会恢复到屏幕底部的位置并遵守位置:固定规则。
还有其他人经历过这种行为吗?这是预期的吗?谢谢。
I have a mobile website which has a div pinned to the bottom of the screen via position:fixed. All works fine in iOS 5 (I'm testing on an iPod Touch) until I'm on a page with a form. When I tap into an input field and the virtual keyboard appears, suddenly the fixed position of my div is lost. The div now scrolls with the page as long as the keyboard is visible. Once I click Done to close the keyboard, the div reverts to its position at the bottom of the screen and obeys the position:fixed rule.
Has anyone else experienced this sort of behavior? Is this expected? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(25)
我在我的应用程序中遇到了这个问题。以下是我解决这个问题的方法:
我只是滚动到顶部并将其放置在那里,因此 iOS 用户不会注意到发生任何奇怪的事情。将其包含在某些用户代理检测中,以便其他用户不会出现此行为。
I had this problem in my application. Here's how I'm working around it:
I'm just scrolling to the top and positioning it there, so the iOS user doesn't notice anything odd going on. Wrap this in some user agent detection so other users don't get this behavior.
我遇到了一个稍微不同的 iPad 问题,虚拟键盘将我的视口推到屏幕外。然后,在用户关闭虚拟键盘后,我的视口仍然在屏幕外。就我而言,我做了类似以下的事情:
I had a slightly different ipad issue where the virtual keyboard pushed my viewport up offscreen. Then after the user closed the virtual keyboard my viewport was still offscreen. In my case I did something like the following:
这是我们用来解决 ipad 问题的代码。它基本上检测偏移和滚动位置之间的差异 - 这意味着“固定”无法正常工作。
This is the code we use to fix problem with ipad. It basically detect discrepancies between offset and scroll position - which means 'fixed' isn't working correctly.
当键盘弹起时,位置固定元素根本不会更新其位置。我发现,通过欺骗 Safari 认为页面已调整大小,元素将重新定位自己。它并不完美,但至少您不必担心切换到“位置:绝对”并自己跟踪更改。
以下代码仅侦听用户何时可能使用键盘(由于输入被聚焦),并且在听到模糊声音之前,它仅侦听任何滚动事件,然后执行调整大小技巧。到目前为止,似乎对我来说工作得很好。
The position fixed elements simply don't update their position when the keyboard is up. I found that by tricking Safari into thinking that the page has resized, though, the elements will re-position themselves. It's not perfect, but at least you don't have to worry about switching to 'position: absolute' and tracking changes yourself.
The following code just listens for when the user is likely to be using the keyboard (due to an input being focused), and until it hears a blur it just listens for any scroll events and then does the resize trick. Seems to be working pretty well for me thus far.
以防万一有人像我在研究这个问题时一样遇到这个线程。我发现这条线索有助于激发我对这个问题的思考。
这是我在最近的项目中对此的解决方案。您只需将“targetElem”的值更改为代表您的标头的 jQuery 选择器。
由于 iOS 在滚动时停止 DOM 操作,修复的实施有一点延迟,但它确实起到了作用……
Just in case somebody happens upon this thread as I did while researching this issue. I found this thread helpful in stimulating my thinking on this issue.
This was my solution for this on a recent project. You just need to change the value of "targetElem" to a jQuery selector that represents your header.
There is a little bit of a delay in the fix taking hold because iOS stops DOM manipulation while it is scrolling, but it does the trick...
我为这个错误找到的其他答案都对我不起作用。我只需将页面向上滚动 34 像素(mobile safari 向下滚动的量)即可修复此问题。 with jquery:
这显然会在所有浏览器中生效,但它会阻止它在 iOS 中崩溃。
None of the other answers I've found for this bug have worked for me. I was able to fix it simply by scrolling the page back up by 34px, the amount mobile safari scrolls it down. with jquery:
This obviously will take effect in all browsers, but it prevents it breaking in iOS.
这个问题确实很烦人。
我结合了上面提到的一些技术并想出了这个:
我有两个固定的导航栏(页眉和页脚,使用 twitter bootstrap)。
当键盘抬起时,两者都表现得很奇怪,而键盘按下后,两者又表现得很奇怪。
通过这个定时/延迟修复,它可以工作。我仍然偶尔会发现一个小故障,但它似乎足以向客户展示它。
让我知道这是否适合您。如果没有,我们也许可以找到其他东西。谢谢。
This issue is really annoying.
I combined some of the above mentioned techniques and came up with this:
I have two fixed navbars (header and footer, using twitter bootstrap).
Both acted weird when the keyboard is up and weird again after keyboard is down.
With this timed/delayed fix it works. I still find a glitch once in a while, but it seems to be good enough for showing it to the client.
Let me know if this works for you. If not we might can find something else. Thanks.
我在 iOS7 上也遇到了同样的问题。底部固定元素会扰乱我的视野,无法正确聚焦。
当我将此元标记添加到我的 html 中时,一切都开始工作。
造成差异的部分是:
希望能帮助别人。
I was experiencing same issue with iOS7. Bottom fixed elements would mess up my view not focus properly.
All started working when I added this meta tag to my html.
The part which made the difference was:
Hope that helps someone.
我采用了
Jory Cunningham
的答案并改进了它:在许多情况下,不仅仅是一个元素发疯,而是几个固定定位的元素,所以在这种情况下,< code>targetElem 应该是一个 jQuery 对象,其中包含您希望“修复”的所有固定元素。呵呵,如果你滚动,这似乎会使 iOS 键盘消失...
不用说,你应该使用这个 AFTER 文档
DOM read
事件或在关闭之前>
标签。I've taken
Jory Cunningham
answer and improved it:In many cases, it's not just one element who goes crazy, but several fixed positioned elements, so in this case,
targetElem
should be a jQuery object which has all the fixed elements you wish to "fix". Ho, this seems to make the iOS keyboard go away if you scroll...Needless to mention you should use this AFTER document
DOM ready
event or just before the closing</body>
tag.我有一个类似于 @NealJMD 的解决方案,除了我的解决方案仅针对 iOS 执行,并通过测量本机键盘滚动之前和之后的 scollTop 以及使用 setTimeout 来允许发生本机滚动来正确确定滚动偏移:
I have a solution similar to @NealJMD except mine only executes for iOS and correctly determines the scroll offset by measuring the scollTop before and after the native keyboard scrolling as well as using setTimeout to allow the native scrolling to occur:
我已经通过这种方式修复了我的 iPad 主布局内容固定位置:
I have fixed my Ipad main layout content fixed position this way:
我遇到了与 @ds111 类似的问题。我的网站被键盘向上推,但键盘关闭时没有向下移动。
首先,我尝试了 @ds111 解决方案,但我有两个输入字段。当然,首先键盘消失,然后模糊发生(或类似的事情)。因此,当焦点直接从一个输入切换到另一个输入时,第二个输入位于键盘下方。
此外,“跳跃”对我来说还不够好,因为整个页面只有 ipad 的大小。所以我让滚动变得平滑。
最后,我必须将事件侦听器附加到所有输入,甚至是当前隐藏的输入,因此是
live
。总而言之,我可以将以下 javascript 片段解释为:
将以下模糊事件侦听器附加到当前和所有未来的
input
和textarea
(=live
):等待宽限期 (=window.setTimeout(..., 10)
) 并平滑滚动到顶部 (=animate({scrollTop: 0}, ...)
) 但前提是“没有显示键盘” " (=if($('输入:焦点, textarea:focus').length == 0)
)。请注意,宽限期 (=
10
) 可能太短,或者尽管没有聚焦input
或textarea
,但键盘仍可能显示。当然,如果您希望滚动更快或更慢,您可以调整持续时间(=400
)I had a similar problem to @ds111 s. My website was pushed up by the keyboard but didn't move down when the keyboard closed.
First I tried @ds111 solution but I had two
input
fields. Of course, first the keyboard goes away, then the blur happens (or something like that). So the secondinput
was under the keyboard, when the focus switched directly from one input to the other.Furthermore, the "jump up" wasn't good enough for me as the whole page only has the size of the ipad. So I made the scroll smooth.
Finally, I had to attach the event listener to all inputs, even those, that were currently hidden, hence the
live
.All together I can explain the following javascript snippet as:
Attach the following blur event listener to the current and all future
input
andtextarea
(=live
): Wait a grace period (=window.setTimeout(..., 10)
) and smoothly scroll to top (=animate({scrollTop: 0}, ...)
) but only if "no keyboard is shown" (=if($('input:focus, textarea:focus').length == 0)
).Be aware, that the grace period (=
10
) may be too short or the keyboard may still be shown although noinput
ortextarea
is focused. Of course, if you want the scrolling faster or slower, you may adjust the duration (=400
)真的很努力地找到这个解决方法,简而言之,它会在输入上查找焦点和模糊事件,并在事件发生时滚动以有选择地更改固定栏的位置。这是防弹的,涵盖所有情况(使用 <>、滚动、完成按钮导航)。注意 id="nav" 是我的固定页脚 div。您可以轻松地将其移植到标准 js 或 jquery。这是为那些使用电动工具的人准备的道场;-)
define([
“道场/准备好”,
“道场/查询”,
], 函数(就绪, 查询){
}); //结束定义
really worked hard to find this workaround, which in short looks for focus and blur events on inputs, and scrolling to selectively change the positioning of the fixed bar when the events happen. This is bulletproof, and covers all cases (navigating with <>, scroll, done button). Note id="nav" is my fixed footer div. You can easily port this to standard js, or jquery. This is dojo for those who use power tools ;-)
define([
"dojo/ready",
"dojo/query",
], function(ready, query){
}); //end define
这是一个很难“正确”解决的问题。您可以尝试在输入元素焦点上隐藏页脚,并在模糊时显示页脚,但这在 iOS 上并不总是可靠。每隔一段时间(例如,在我的 iPhone 4S 上,十分之一)焦点事件似乎无法触发(或者可能存在竞争条件),并且页脚不会被隐藏。
经过多次尝试和错误,我想出了这个有趣的解决方案:
本质上:使用 JavaScript 确定设备的窗口高度,然后动态创建 CSS 媒体查询,以在窗口高度缩小 10 像素时隐藏页脚。因为打开键盘会调整浏览器显示的大小,所以这在 iOS 上永远不会失败。因为它使用 CSS 引擎而不是 JavaScript,所以速度更快、更流畅!
注意:我发现使用“visibility:hidden”比“display:none”或“position:static”的故障少,但您的情况可能会有所不同。
This is a difficult problem to get 'right'. You can try and hide the footer on input element focus, and show on blur, but that isn't always reliable on iOS. Every so often (one time in ten, say, on my iPhone 4S) the focus event seems to fail to fire (or maybe there is a race condition), and the footer does not get hidden.
After much trial and error, I came up with this interesting solution:
Essentially: use JavaScript to determine the window height of the device, then dynamically create a CSS media query to hide the footer when the height of the window shrinks by 10 pixels. Because opening the keyboard resizes the browser display, this never fails on iOS. Because it's using the CSS engine rather than JavaScript, it's much faster and smoother too!
Note: I found using 'visibility:hidden' less glitchy than 'display:none' or 'position:static', but your mileage may vary.
对我有用
Works for me
在我们的例子中,一旦用户滚动,这个问题就会自行修复。因此,这是我们一直用来在任何
input
或textarea
上模拟blur
滚动的修复:In our case this would fix itself as soon as user scrolls. So this is the fix we've been using to simulate a scroll on
blur
on anyinput
ortextarea
:我的回答是做不到。
我看到 25 个答案,但没有一个适合我的情况。这就是为什么雅虎和其他页面在键盘打开时隐藏固定标题的原因。 Bing 将整个页面设置为不可滚动(overflow-y:隐藏)。
上面讨论的情况各不相同,有些在滚动时出现问题,有些在焦点或模糊时出现问题。有些有固定的页脚或页眉。我现在无法测试每种组合,但您最终可能会意识到在您的情况下无法完成。
My answer is that it can't be done.
I see 25 answers but none work in my case. That's why Yahoo and other pages hide the fixed header when the keyboard is on. And Bing turns the whole page non-scrollable (overflow-y: hidden).
The cases discussed above are different, some have issues when scrolling, some on focus or blur. Some have fixed footer, or header. I can't test now each combination, but you might end up realizing that it can't be done in your case.
在Github上找到了这个解决方案。
https://github.com/Simbul/baker/issues/504#issuecomment-12821392
确保您有可滚动的内容。
地址栏可以折叠起来作为额外的好处。
Found this solution on Github.
https://github.com/Simbul/baker/issues/504#issuecomment-12821392
Make sure you have scrollable content.
The address bar folds up as an added bonus.
万一有人想尝试这个。我在带有输入字段的固定页脚上得到了以下工作。
In case anyone wanted to try this. I got the following working for me on a fixed footer with an inputfield in it.
我有同样的问题。但我意识到固定位置只是延迟而不是打破(至少对我来说)。等待 5-10 秒,查看 div 是否调整回屏幕底部。我相信这不是错误,而是键盘打开时的延迟响应。
I have the same issue. But I realized that the fixed position is just delayed and not broken (at least for me). Wait 5-10 seconds and see if the div adjusts back to the bottom of the screen. I believe it's not an error but a delayed response when the keyboard is open.
我尝试了该线程中的所有方法,但如果它们没有帮助,那就更糟了。
最后,我决定强制设备失去焦点:
它就像一个魅力,修复了我粘性的登录表单。
请注意:
jQuery v1.10.2
配合使用I tried all the approaches from this thread, but if they didn't help, they did even worse.
In the end, I decided force device to loose focus:
and it worked like a charm and fixed my sticky login-form.
Please NOTE:
jQuery v1.10.2
对于 iOS 8.3 中具有较高 Bootstrap Modals 的任何 HTML 页面来说,这仍然是一个大错误。上面提出的解决方案都不起作用,并且在放大高模态折叠下方的任何字段后,Mobile Safari 和/或 WkWebView 会将固定元素移动到 HTML 主体滚动所在的位置,使它们与它们的位置不对齐实际上是在哪里布置的。
要解决该错误,请向任何模态输入添加一个事件侦听器,例如:
我猜这会起作用,因为强制 HTML 正文的滚动高度会将实际视图与 iOS 8 WebView 期望固定模态 div 内容的位置重新对齐。
This is still a large bug for for any HTML pages with taller Bootstrap Modals in iOS 8.3. None of the proposed solutions above worked and after zooming in on any field below the fold of a tall modal, Mobile Safari and/or WkWebView would move the fixed elements to where the HTML body's scroll was situated, leaving them misaligned with where they actually where laid out.
To workaround the bug, add an event listener to any of your modal inputs like:
I'm guessing this works because forcing the HTML body's scroll height re-aligns the actual view with where the iOS 8 WebView expects the fixed modal div's contents to be.
如果有人正在寻找完全不同的路线(就像您在滚动时甚至不希望固定这个“页脚”div,但您只是希望该 div 停留在页面底部),您可以将页脚位置设置为相对的。
这意味着即使虚拟键盘出现在您的移动浏览器上,您的页脚也只会锚定在页面底部,而不是试图对虚拟键盘的显示或关闭做出反应。
显然,如果位置是固定的,并且当您向上或向下滚动时页脚跟随页面,那么它在 Safari 上看起来会更好,但由于 Chrome 上的这个奇怪的错误,我们最终切换到仅使页脚相对。
If anybody was looking for a completely different route (like you are not even looking to pin this "footer" div as you scroll but you just want the div to stay at the bottom of the page), you can just set the footer position as relative.
That means that even if the virtual keyboard comes up on your mobile browser, your footer will just stay anchored to the bottom of the page, not trying to react to virtual keyboard show or close.
Obviously it looks better on Safari if position is fixed and the footer follows the page as you scroll up or down but due to this weird bug on Chrome, we ended up switching over to just making the footer relative.
滚动解决方案似乎都不适合我。相反,有效的方法是在用户编辑文本时将正文的位置设置为固定,然后在用户完成后将其恢复为静态。这可以防止 Safari 在您身上滚动您的内容。您可以在元素的焦点/模糊上执行此操作(如下所示为单个元素,但可能适用于所有输入、文本区域),或者如果用户正在执行某些操作来开始编辑(例如打开模式),您可以执行以下操作它在该操作上(例如模态打开/关闭)。
None of the scrolling solutions seemed to work for me. Instead, what worked is to set the position of the body to fixed while the user is editing text and then restore it to static when the user is done. This keeps safari from scrolling your content on you. You can do this either on focus/blur of the element(s) (shown below for a single element but could be for all input, textareas), or if a user is doing something to begin editing like opening a modal, you can do it on that action (e.g. modal open/close).
iOS9 - 同样的问题。
TLDR - 问题的根源。如需解决方案,滚动到底部
我在
position:fixed
iframe 中有一个表单,其 id='subscribe-popup-frame'根据最初的问题,在输入焦点上,iframe 会转到到文档的顶部而不是屏幕的顶部。
在将用户代理设置为 idevice 的 safari 开发模式下,不会出现同样的问题。所以看来问题是由iOS虚拟键盘弹出时引起的。
我通过控制台记录 iframe 的位置(例如
$('#subscribe-popup-frame', window.parent.document).position()
)了解了发生的情况,从那里我可以看到当虚拟键盘弹出时(即聚焦在输入元素上),iOS 似乎将元素的位置设置为{top: -x, left: 0}
。所以我的解决方案是采用那个讨厌的
-x
,反转符号,然后使用 jQuery 将top
位置添加回 iframe。如果有更好的解决方案,我很想听到它,但在尝试了十几种不同的方法之后,这是唯一对我有用的方法。缺点:我需要设置 500 毫秒的超时(也许更短也可以,但我想安全),以确保在 iOS 完成其操作后捕获最终的x 值元素位置的恶作剧。结果就是体验非常生涩。 。 。但至少它可以工作
解决方案
然后只需调用
mobileInputReposition
类似$('your-input-field).focus(function(){}) 和
$('your-input-field).blur(function(){})
iOS9 - same problem.
TLDR - source of the problem. For solution, scroll to bottom
I had a form in a
position:fixed
iframe with id='subscribe-popup-frame'As per the original question, on input focus the iframe would go to the top of the document as opposed to the top of the screen.
The same problem did not occur in safari dev mode with user agent set to an idevice. So it seems the problem is caused by iOS virtual keyboard when it pops up.
I got some visibility into what was happening by console logging the iframe's position (e.g.
$('#subscribe-popup-frame', window.parent.document).position()
) and from there I could see iOS seemed to be setting the position of the element to{top: -x, left: 0}
when the virtual keyboard popped up (i.e. focussed on the input element).So my solution was to take that pesky
-x
, reverse the sign and then use jQuery to add thattop
position back to the iframe. If there is a better solution I would love to hear it but after trying a dozen different approaches it was the only one that worked for me.Drawback: I needed to set a timeout of 500ms (maybe less would work but I wanted to be safe) to make sure I captured the final
x
value after iOS had done its mischief with the position of the element. As a result, the experience is very jerky . . . but at least it worksSolution
Then just call
mobileInputReposition
in something like$('your-input-field).focus(function(){})
and$('your-input-field).blur(function(){})