IOS5固定定位和虚拟键盘

我有一个手机网站,有一个 div 固定在屏幕底部的位置: 固定。在 iOS5(我正在测试 iPodTouch)中,所有这些都能正常工作,直到我进入一个有表单的页面。当我点击一个输入字段并出现虚拟键盘时,突然丢失了 div 的固定位置。现在,只要键盘可见,div 就会随页面滚动。一旦我点击完成关闭键盘,div 恢复到它在屏幕底部的位置,并遵守位置: 固定规则。

还有其他人经历过这种行为吗? 这是预料之中的吗? 谢谢。

68876 次浏览

位置固定元素只是不更新他们的位置时,键盘上。我发现,通过欺骗 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;
});

我找到的所有解决这个问题的方法都不适合我。我只需要把页面向上滚动34px 就可以修复这个问题,移动 Safari 向下滚动的幅度相当于34px。使用 jquery:

$('.search-form').on('focusin', function(){
$(window).scrollTop($(window).scrollTop() + 34);
});

这显然会在所有的浏览器中生效,但是它可以防止它在 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);
}
});

以防有人像我一样在研究这个问题时碰到这个话题。我发现这个帖子有助于激发我对这个问题的思考。

这是我在最近的一个项目中对此的解决方案。您只需要将“ 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 的操作,所以在修复过程中有一点延迟,但它确实起到了作用..。

我在申请中遇到了这个问题,我是这样解决的:

input.on('focus', function(){
header.css({position:'absolute'});
});
input.on('blur', function(){
header.css({position:'fixed'});
});

我只需要滚动到顶部并把它放在那里,这样 iOS 用户就不会注意到任何奇怪的事情发生。在某些用户代理检测中包装这一点,这样其他用户就不会得到这种行为。

在 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>

我也有同样的问题。但是我意识到,固定的位置只是延迟,而不是中断(至少对我来说)。等待5-10秒钟,看看 div 是否调整回屏幕底部。我相信这不是一个错误,而是键盘打开时的延迟反应。

我用这种方式固定了我的 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);

这个问题真的很烦人。

我综合了上面提到的一些技巧,得出了以下结论:

$(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);
});

我有两个固定的导航栏(页眉和页脚,使用 Bootstrap)。 当键盘在上时,两人都表现得很奇怪,当键盘在下时,两人又表现得很奇怪。

有了这个定时/延迟的修复程序,它就可以工作了。我偶尔还是会发现一些小故障,但似乎已经足够向客户展示了。

让我知道这是否适合你。如果不是,我们可能会找到其他的东西。谢谢。

我尝试了这个线程中的所有方法,但是如果它们没有帮助,那么它们会做得更糟。 最后,我决定迫使设备失去焦点:

$(<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);
}
});

它的工作像一个魅力和固定我的粘性登录表单。

注意:

  1. 上面的 JS 代码只是为了展示我的想法,为了执行这个代码片段,请根据您的情况使用适当的值替换角括号(< >)中的值。
  2. 这段代码被设计用于 jQuery v1.10.2

我也遇到过类似的问题@ds111s。我的网站被键盘推高了,但是当键盘关闭时却没有下移。

首先我尝试了@ds111解决方案,但是我有两个 input字段。当然,首先键盘消失,然后模糊发生(或类似的事情)。因此,第二个 input是在键盘下面,当焦点直接从一个输入切换到另一个。

此外,“跳起来”对我来说还不够好,因为整个页面只有 ipad 的大小。所以我把卷轴做得很光滑。

最后,我必须将事件侦听器附加到所有输入,甚至是那些当前隐藏的输入,因此使用 live

总之,我可以解释下面的 javascript 代码片段: 将以下模糊事件监听器附加到当前和所有未来的 inputtextarea(= 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)可能太短,或键盘可能仍然显示,虽然没有 inputtextarea是集中。当然,如果您希望滚动更快或更慢,您可以调整持续时间(= 400)

真的努力工作找到这个变通方法,在短期寻找焦点和模糊事件的输入,滚动选择性地改变固定栏的位置时,事件发生。这是防弹的,并涵盖所有情况(导航与 < > ,滚动,完成按钮)。注意 id = “ nav”是我的固定脚注 div。您可以轻松地将其移植到标准 js 或 jquery。这是为那些使用电动工具的人准备的道场; -)

定义([ “道场准备” “道场/查询” 函数(ready,query){

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 );
}


});

}) ;//结束定义

我有一个类似@NealJMD 的解决方案,只不过我的解决方案只能在 iOS 上执行,并且通过测量原生键盘滚动之前和之后的 scolTop,以及使用 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);
}

这是一个很难做到“正确”的问题。你可以尝试隐藏输入元素焦点的页脚,在模糊处显示,但是这在 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,所以它也更快更流畅!

注意: 我发现使用“可见性: 隐藏”比“显示: 无”或“位置: 静态”更容易出错,但你的里程数可能会有所不同。

我没问题

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'});
});
}

我采用了 Jory Cunningham的答案并改进了它:

在许多情况下,发疯的不仅仅是一个元素,而是几个固定位置的元素,所以在这种情况下,targetElem应该是一个 jQuery 对象,其中包含所有您希望“修复”的固定元素。Ho,这似乎使 iOS 键盘消失,如果你滚动..。

不用说,您应该使用这个 之后文档 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');
}
})();

在我们的例子中,这将在用户滚动时自动修复。这就是我们在 input或者 textarea上用来模拟 blur上的滚动的方法:

$(document).on('blur', 'input, textarea', function () {
setTimeout(function () {
window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
}, 0);
});

我在 iOS7上也遇到了同样的问题。底部的固定元素会把我的视图弄乱,不能正确对焦。

当我将这个 meta 标记添加到 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

希望这对某人有帮助。

对于任何在 iOS 8.3中使用较高 Bootstrap Modals 的 HTML 页面来说,这仍然是一个很大的 bug。上面提出的解决方案没有一个奏效,在放大高模式折叠下的任何区域后,Mobile Safari 和/或 WkWebView 会将固定元素移动到 HTML 主体滚动条所在的位置,使它们与放置它们的 事实上不一致。

要解决这个问题,可以在任何模态输入中添加一个事件侦听器,比如:

$(select.modal).blur(function(){
$('body').scrollTop(0);
});

我猜测这是因为强制 HTML 主体的滚动高度使实际视图与 iOS8 WebView 期望固定模态 div 内容的位置重新对齐。

如果有人正在寻找一个完全不同的路径(比如你甚至不想在滚动时固定这个“ footer”div,而只是想让这个 div 保持在页面的底部) ,你可以将 footer 的位置设置为相对位置。

这意味着即使虚拟键盘出现在你的移动浏览器上,你的页脚也只会固定在页面的底部,而不会对虚拟键盘显示或关闭做出反应。

显然,如果位置是固定的,页脚跟随页面向上或向下滚动,那么在 Safari 上看起来会更好,但是由于 Chrome 上的这个奇怪的 bug,我们最终切换到只是让页脚相对。

所有的滚动解决方案似乎都不适合我。相反,工作原理是在用户编辑文本时将主体的位置设置为固定,然后在用户编辑完成后将其恢复为静态。这样可以防止你的内容在你身上滚动。你可以对元素进行焦点/模糊处理(下面显示的是单个元素的焦点/模糊处理,但也可以是所有输入、文本区域的焦点/模糊处理) ,或者如果用户正在做某些事情来开始编辑,比如打开一个模态,你可以在那个动作上进行(例如模态打开/关闭)。

$("#myInput").on("focus", function () {
$("body").css("position", "fixed");
});


$("#myInput").on("blur", function () {
$("body").css("position", "static");
});

IOS9——同样的问题。

TLDR-问题的根源。要获得解决方案,请滚动到底部

我在一个 position:fixed iframe 中有一个表单,id =’订阅-弹出框’

根据最初的问题,在输入焦点上,iframe 将位于文档的顶部,而不是屏幕的顶部。

在将用户代理设置为设备的 safari dev 模式中没有出现同样的问题。因此,这个问题似乎是由 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);
}
}

然后在类似 $('your-input-field).focus(function(){})$('your-input-field).blur(function(){})的地方调用 mobileInputReposition

我的回答是,这是不可能的。

我看到了25个答案,但没有一个对我有用。这就是为什么雅虎和其他网页隐藏固定的标题时,键盘上。Bing 使整个页面不可滚动(overflow-y: hide)。

上面讨论的情况是不同的,一些在滚动时有问题,一些在焦点或模糊。有些有固定的页脚或页眉。我现在不能测试每种组合,但是你可能最终会意识到,这在你的情况下是不可能做到的。