我有一个移动网站,其中有一个通过位置固定到屏幕底部的 div:固定。在 iOS 5 中一切正常(我正在 iPod Touch 上进行测试),直到我在带有表单的页面上。当我点击输入字段并出现虚拟键盘时,突然我的 div 的固定位置丢失了。只要键盘可见,div 现在就会随着页面滚动。单击完成关闭键盘后,div 将恢复到屏幕底部的位置并遵守 position:fixed 规则。
有没有其他人经历过这种行为?这是预期的吗?谢谢。
我有一个移动网站,其中有一个通过位置固定到屏幕底部的 div:固定。在 iOS 5 中一切正常(我正在 iPod Touch 上进行测试),直到我在带有表单的页面上。当我点击输入字段并出现虚拟键盘时,突然我的 div 的固定位置丢失了。只要键盘可见,div 现在就会随着页面滚动。单击完成关闭键盘后,div 将恢复到屏幕底部的位置并遵守 position:fixed 规则。
有没有其他人经历过这种行为?这是预期的吗?谢谢。
我在我的应用程序中遇到了这个问题。这是我解决它的方法:
input.on('focus', function(){
header.css({position:'absolute'});
});
input.on('blur', function(){
header.css({position:'fixed'});
});
我只是滚动到顶部并将其定位在那里,所以 iOS 用户不会注意到任何奇怪的事情发生。将此包装在一些用户代理检测中,以便其他用户不会得到这种行为。
我有一个稍微不同的 ipad 问题,虚拟键盘将我的视口推到屏幕外。然后在用户关闭虚拟键盘后,我的视口仍然在屏幕外。就我而言,我做了以下事情:
var el = document.getElementById('someInputElement');
function blurInput() {
window.scrollTo(0, 0);
}
el.addEventListener('blur', blurInput, false);
这是我们用来解决 ipad 问题的代码。它基本上检测偏移和滚动位置之间的差异 - 这意味着“固定”无法正常工作。
$(window).bind('scroll', function () {
var $nav = $(".navbar")
var scrollTop = $(window).scrollTop();
var offsetTop = $nav.offset().top;
if (Math.abs(scrollTop - offsetTop) > 1) {
$nav.css('position', 'absolute');
setTimeout(function(){
$nav.css('position', 'fixed');
}, 1);
}
});
当键盘打开时,位置固定元素根本不会更新它们的位置。我发现通过诱使 Safari 认为页面已经调整大小,但是,元素会重新定位自己。它并不完美,但至少您不必担心切换到“位置:绝对”并自己跟踪变化。
下面的代码只监听用户何时可能正在使用键盘(由于输入被聚焦),并且在它听到模糊之前它只监听任何滚动事件,然后执行调整大小的技巧。到目前为止,似乎对我来说工作得很好。
var needsScrollUpdate = false;
$(document).scroll(function(){
if(needsScrollUpdate) {
setTimeout(function() {
$("body").css("height", "+=1").css("height", "-=1");
}, 0);
}
});
$("input, textarea").live("focus", function(e) {
needsScrollUpdate = true;
});
$("input, textarea").live("blur", function(e) {
needsScrollUpdate = false;
});
以防万一有人像我在研究这个问题时那样发生在这个线程上。我发现这个线程有助于激发我对这个问题的思考。
这是我在最近的一个项目中的解决方案。您只需将“targetElem”的值更改为代表您的标头的 jQuery 选择器。
if(navigator.userAgent.match(/iPad/i) != null){
var iOSKeyboardFix = {
targetElem: $('#fooSelector'),
init: (function(){
$("input, textarea").on("focus", function() {
iOSKeyboardFix.bind();
});
})(),
bind: function(){
$(document).on('scroll', iOSKeyboardFix.react);
iOSKeyboardFix.react();
},
react: function(){
var offsetX = iOSKeyboardFix.targetElem.offset().top;
var scrollX = $(window).scrollTop();
var changeX = offsetX - scrollX;
iOSKeyboardFix.targetElem.css({'position': 'fixed', 'top' : '-'+changeX+'px'});
$('input, textarea').on('blur', iOSKeyboardFix.undo);
$(document).on('touchstart', iOSKeyboardFix.undo);
},
undo: function(){
iOSKeyboardFix.targetElem.removeAttr('style');
document.activeElement.blur();
$(document).off('scroll',iOSKeyboardFix.react);
$(document).off('touchstart', iOSKeyboardFix.undo);
$('input, textarea').off('blur', iOSKeyboardFix.undo);
}
};
};
由于 iOS 在滚动时停止了 DOM 操作,因此修复存在一点延迟,但它确实起到了作用......
这个问题真的很烦人。
我结合了上面提到的一些技术并想出了这个:
$(document).on('focus', 'input, textarea', function() {
$('.YOUR-FIXED-DIV').css('position', 'static');
});
$(document).on('blur', 'input, textarea', function() {
setTimeout(function() {
$('.YOUR-FIXED-DIV').css('position', 'fixed');
$('body').css('height', '+=1').css('height', '-=1');
}, 100);
});
我有两个固定的导航栏(页眉和页脚,使用 twitter 引导程序)。键盘启动时两者都表现得很奇怪,键盘关闭后又很奇怪。
通过这个定时/延迟修复它可以工作。我仍然偶尔会发现一个小故障,但它似乎足以向客户展示它。
让我知道这是否适合您。如果没有,我们可能会找到其他东西。谢谢。
我在使用 iOS7 时遇到了同样的问题。底部固定元素会弄乱我的视图,无法正确聚焦。
当我将此元标记添加到我的 html 时,一切都开始工作了。
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no,height=device-height" >
造成差异的部分是:
height=device-height
希望对某人有所帮助。
我为这个错误找到的其他答案都没有对我有用。我可以通过将页面向上滚动 34px 来修复它,移动 safari 的数量会将其向下滚动。用jQuery:
$('.search-form').on('focusin', function(){
$(window).scrollTop($(window).scrollTop() + 34);
});
这显然会在所有浏览器中生效,但它可以防止它在 iOS 中中断。
我已经Jory Cunningham
回答并改进了它:
在很多情况下,发疯的不仅仅是一个元素,而是几个固定定位的元素,所以在这种情况下,targetElem
应该是一个 jQuery 对象,其中包含您希望“修复”的所有固定元素。嗬,如果你滚动,这似乎会让 iOS 键盘消失......
不用说,您应该使用这个AFTER文档DOM ready
事件或在结束</body>
标记之前。
(function(){
var targetElem = $('.fixedElement'), // or more than one
$doc = $(document),
offsetY, scrollY, changeY;
if( !targetElem.length || !navigator.userAgent.match(/iPhone|iPad|iPod/i) )
return;
$doc.on('focus.iOSKeyboardFix', 'input, textarea, [contenteditable]', bind);
function bind(){
$(window).on('scroll.iOSKeyboardFix', react);
react();
}
function react(){
offsetY = targetElem.offset().top;
scrollY = $(window).scrollTop();
changeY = offsetY - scrollY;
targetElem.css({'top':'-'+ changeY +'px'});
// Instead of the above, I personally just do:
// targetElem.css('opacity', 0);
$doc.on('blur.iOSKeyboardFix', 'input, textarea, [contenteditable]', unbind)
.on('touchend.iOSKeyboardFix', unbind);
}
function unbind(){
targetElem.removeAttr('style');
document.activeElement.blur();
$(window).off('scroll.iOSKeyboardFix');
$doc.off('touchend.iOSKeyboardFix blur.iOSKeyboardFix');
}
})();
我有一个类似于@NealJMD 的解决方案,除了我的仅适用于 iOS 并通过测量本机键盘滚动前后的 scollTop 以及使用 setTimeout 来允许发生本机滚动来正确确定滚动偏移量:
var $window = $(window);
var initialScroll = $window.scrollTop();
if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
setTimeout(function () {
$window.scrollTop($window.scrollTop() + (initialScroll - $window.scrollTop()));
}, 0);
}
我遇到了与@ds111 类似的问题。我的网站被键盘向上推,但在键盘关闭时没有向下移动。
首先我尝试了@ds111 解决方案,但我有两个input
字段。当然,首先键盘消失,然后出现模糊(或类似情况)。所以第二个input
是在键盘下,当焦点直接从一个输入切换到另一个时。
此外,“跳起来”对我来说还不够好,因为整个页面只有 ipad 的大小。所以我使滚动平滑。
最后,我必须将事件侦听器附加到所有输入,甚至是那些当前隐藏的输入,因此live
.
总之,我可以将以下 javascript 片段解释为:将以下模糊事件侦听器附加到当前和所有未来input
和textarea
(= live
):等待宽限期 (= window.setTimeout(..., 10)
) 并平滑滚动到顶部 (= animate({scrollTop: 0}, ...)
),但前提是“没有键盘是显示”(= if($('input:focus, textarea:focus').length == 0)
)。
$('input, textarea').live('blur', function(event) {
window.setTimeout(function() {
if($('input:focus, textarea:focus').length == 0) {
$("html, body").animate({ scrollTop: 0 }, 400);
}
}, 10)
})
请注意,宽限期 (= 10
) 可能太短,或者键盘可能仍会显示,尽管没有焦点input
或textarea
焦点。当然,如果您希望滚动更快或更慢,您可以调整持续时间(= 400
)
为我工作
if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
$(document).on('focus', 'input, textarea', function() {
$('header').css({'position':'static'});
});
$(document).on('blur', 'input, textarea', function() {
$('header').css({'position':'fixed'});
});
}
在我们的例子中,一旦用户滚动,它就会自行修复。所以这是我们一直用来模拟blur
在 any input
or上滚动的修复textarea
:
$(document).on('blur', 'input, textarea', function () {
setTimeout(function () {
window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
}, 0);
});
这是一个很难“正确”的问题。您可以尝试在输入元素焦点上隐藏页脚,并在模糊时显示,但这在 iOS 上并不总是可靠的。每隔一段时间(十分之一,比如说,在我的 iPhone 4S 上),焦点事件似乎无法触发(或者可能存在竞争条件),并且页脚没有被隐藏。
经过反复试验,我想出了这个有趣的解决方案:
<head>
...various JS and CSS imports...
<script type="text/javascript">
document.write( '<style>#footer{visibility:hidden}@media(min-height:' + ($( window ).height() - 10) + 'px){#footer{visibility:visible}}</style>' );
</script>
</head>
本质上:使用 JavaScript 确定设备的窗口高度,然后动态创建 CSS 媒体查询以在窗口高度缩小 10 像素时隐藏页脚。因为打开键盘会调整浏览器显示的大小,所以这在 iOS 上永远不会失败。因为它使用的是 CSS 引擎而不是 JavaScript,所以它也更快更流畅!
注意:我发现使用 'visibility:hidden' 比使用 'display:none' 或 'position:static' 更少故障,但你的里程可能会有所不同。
真的很努力地找到这个解决方法,简而言之,它会在输入上查找焦点和模糊事件,并在事件发生时滚动以选择性地更改固定栏的位置。这是防弹的,涵盖所有情况(使用 <> 导航、滚动、完成按钮)。注意 id="nav" 是我的固定页脚 div。您可以轻松地将其移植到标准 js 或 jquery。这是使用电动工具的人的道场;-)
定义([“道场/就绪”,“道场/查询”,],函数(就绪,查询){
ready(function(){
/* This addresses the dreaded "fixed footer floating when focusing inputs and keybard is shown" on iphone
*
*/
if(navigator.userAgent.match(/iPhone/i)){
var allInputs = query('input,textarea,select');
var d = document, navEl = "nav";
allInputs.on('focus', function(el){
d.getElementById(navEl).style.position = "static";
});
var fixFooter = function(){
if(d.activeElement.tagName == "BODY"){
d.getElementById(navEl).style.position = "fixed";
}
};
allInputs.on('blur', fixFooter);
var b = d.body;
b.addEventListener("touchend", fixFooter );
}
});
}); //结束定义
我以这种方式修复了我的 Ipad 主要布局内容固定位置:
var mainHeight;
var main = $('.main');
// hack to detects the virtual keyboard close action and fix the layout bug of fixed elements not being re-flowed
function mainHeightChanged() {
$('body').scrollTop(0);
}
window.setInterval(function () {
if (mainHeight !== main.height())mainHeightChanged();
mainHeight = main.height();
}, 100);
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.
我尝试了该线程中的所有方法,但如果它们没有帮助,它们会做得更糟。最后,我决定强制设备放松焦点:
$(<selector to your input field>).focus(function(){
var $this = $(this);
if (<user agent target check>) {
function removeFocus () {
$(<selector to some different interactive element>).focus();
$(window).off('resize', removeFocus);
}
$(window).on('resize', removeFocus);
}
});
它就像一个魅力并修复了我的粘性登录表单。
请注意:
jQuery v1.10.2
我有同样的问题。但我意识到,固定位置只是延迟而不是中断(至少对我而言)。等待 5-10 秒,看看 div 是否调整回屏幕底部。我相信这不是错误,而是打开键盘时的延迟响应。
在 Github 上找到了这个解决方案。
https://github.com/Simbul/baker/issues/504#issuecomment-12821392
确保您有可滚动的内容。
// put in your .js file
$(window).load(function(){
window.scrollTo(0, 1);
});
// min-height set for scrollable content
<div id="wrap" style="min-height: 480px">
// website goes here
</div>
地址栏折叠起来是一个额外的好处。
万一有人想试试这个。我在一个带有输入字段的固定页脚上为我工作了以下内容。
<script>
$('document').ready(
function() {
if (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)
|| navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i)) {
var windowHeight = $(window).height();
var documentHeight = $(document).height();
$('#notes').live('focus', function() {
if (documentHeight > windowHeight) {
$('#controlsContainer').css({
position : 'absolute'
});
$("html, body").animate({
scrollTop : $(document).height()
}, 1);
}
});
$('#notes').live('blur', function() {
$('#controlsContainer').css({
position : 'fixed'
});
$("html, body").animate({
scrollTop : 0
}, 1);
});
}
});
</script>
对于 iOS 8.3 中具有更高 Bootstrap 模态的任何 HTML 页面,这仍然是一个大错误。上面提出的解决方案都不起作用,并且在放大高模态折叠下方的任何字段后,Mobile Safari 和/或 WkWebView 会将固定元素移动到 HTML 正文的滚动所在的位置,使它们与实际位置不一致布置。
要解决该错误,请将事件侦听器添加到任何模态输入,例如:
$(select.modal).blur(function(){
$('body').scrollTop(0);
});
我猜这是可行的,因为强制 HTML 主体的滚动高度重新对齐实际视图与 iOS 8 WebView 期望固定模态 div 的内容的位置。
iOS9 - 同样的问题。
TLDR - 问题的根源。如需解决方案,请滚动至底部
position:fixed
我在id='subscribe-popup-frame'的 iframe 中有一个表单
根据原始问题,在输入焦点上,iframe 将转到文档顶部,而不是屏幕顶部。
在将用户代理设置为 idevice 的 safari 开发模式下没有发生同样的问题。所以这个问题似乎是由iOS虚拟键盘弹出时引起的。
通过控制台记录 iframe 的位置(例如),我对正在发生的事情有了一些了解$('#subscribe-popup-frame', window.parent.document).position()
,从那里我可以看到 iOS 似乎将元素的位置设置为{top: -x, left: 0}
虚拟键盘弹出时(即专注于输入元素)。
所以我的解决方案是采取那个讨厌-x
的,反转符号,然后使用 jQuery 将该top
位置添加回 iframe。如果有更好的解决方案,我很想听听,但是在尝试了十几种不同的方法之后,它是唯一对我有用的方法。
缺点:我需要设置 500 毫秒的超时时间(可能会更少,但我想保证安全),以确保x
在 iOS 对元素的位置进行恶作剧之后捕获最终值。结果,体验非常生涩。. . 但至少它有效
解决方案
var mobileInputReposition = function(){
//if statement is optional, I wanted to restrict this script to mobile devices where the problem arose
if(screen.width < 769){
setTimeout(function(){
var parentFrame = $('#subscribe-popup-frame',window.parent.document);
var parentFramePosFull = parentFrame.position();
var parentFramePosFlip = parentFramePosFull['top'] * -1;
parentFrame.css({'position' : 'fixed', 'top' : parentFramePosFlip + 'px'});
},500);
}
}
然后只需调用类似的mobileInputReposition
东西$('your-input-field).focus(function(){})
$('your-input-field).blur(function(){})
如果有人正在寻找一条完全不同的路线(例如,您甚至不想在滚动时固定此“页脚” div,而只是希望 div 留在页面底部),您只需将页脚位置设置为相对的。
这意味着即使虚拟键盘出现在您的移动浏览器上,您的页脚也只会停留在页面底部,而不是尝试对虚拟键盘显示或关闭做出反应。
显然,如果位置是固定的,并且当您向上或向下滚动时页脚跟随页面,那么在 Safari 上看起来会更好,但是由于 Chrome 上的这个奇怪的错误,我们最终切换到仅使页脚相对。
滚动解决方案似乎都不适合我。相反,有效的方法是在用户编辑文本时将正文的位置设置为固定,然后在用户完成后将其恢复为静态。这可以防止 Safari 在您身上滚动您的内容。您可以在元素的焦点/模糊上执行此操作(如下所示,针对单个元素,但可能针对所有输入,文本区域),或者如果用户正在执行某些操作以开始编辑,例如打开模式,您可以执行它在那个动作上(例如模式打开/关闭)。
$("#myInput").on("focus", function () {
$("body").css("position", "fixed");
});
$("#myInput").on("blur", function () {
$("body").css("position", "static");
});