iOS 5固定定位和虚拟键盘



我有一个移动网站,其中有一个div通过位置固定在屏幕底部:固定。在iOS 5中(我正在iPod Touch上进行测试),一切都运行良好,直到我进入一个带有表单的页面。当我点击输入字段并出现虚拟键盘时,div的固定位置突然丢失了。div现在随着页面滚动,只要键盘是可见的。一旦我点击Done关闭键盘,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使其认为页面已经调整大小,元素将重新定位自己。这不是完美的,但至少你不必担心切换到"position: absolute"和跟踪自己的变化。

下面的代码只监听用户何时可能使用键盘(由于输入被聚焦),直到听到模糊,它只监听任何滚动事件,然后执行调整大小的技巧。到目前为止,我似乎工作得很好。

    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操作,但它确实奏效了……

我为这个bug找到的其他答案都不适合我。我能够简单地通过将页面向上滚动34px来修复它,这是移动safari向下滚动的数量。jquery:

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

这显然会在所有浏览器中生效,但它可以防止在iOS中破坏。

这个问题真的很烦人。

我结合了上面提到的一些技巧,想出了这个:

$(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 bootstrap)。当键盘向上时,它们都表现得很奇怪,当键盘向下时,它们又表现得很奇怪。

使用这个定时/延迟修复它可以工作。我仍然偶尔会发现一个小故障,但它似乎足够好,可以向客户展示它。

让我知道这是否适合你。如果没有,我们也许能找到别的办法。谢谢。

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

希望这能帮助到别人。

我已经取了 Jory Cunningham 答案并改进了:

在很多情况下,不仅仅是一个元素发疯了,而是几个固定位置的元素发疯了,所以在这种情况下,targetElem应该是一个jQuery对象,它包含了你想要"修复"的所有固定元素。这似乎让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');
    }
})();

我有一个类似于@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);
}

我已经固定了我的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);

我遇到了与@ds111 s类似的问题。我的网站可以通过键盘向上推,但是当键盘关闭时,它不会向下移动。

首先我尝试了@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。这是dojo为那些使用电动工具的人;-)

定义(["dojo/准备","dojo/查询",, function(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 );
    }
});

});//end define

这是一个很难解决的问题。你可以尝试在输入元素聚焦时隐藏页脚,在模糊时显示,但这在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"更少出现故障,但你的实际情况可能会有所不同。

Works for me

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

在我们的例子中,这将在用户滚动后自行修复。这就是我们在inputtextarea上模拟blur滚动的修复方法:

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

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

我看到25个答案,但没有一个适合我。这就是为什么雅虎和其他网页在打开键盘时隐藏固定标题的原因。Bing把整个页面变成不可滚动的

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

在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是否调整回屏幕底部。我相信这不是错误,而是键盘打开时的延迟响应。

我尝试了所有的方法,但如果他们没有帮助,他们做得更糟。最后,我决定强制设备散焦:

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

,它像一个魅力,解决了我的粘性登录表单。

注意:

    上面的JS代码只是为了表达我的想法,要执行这个代码片段,请将角括号(<>)中的值替换为适合您情况的值。
  1. 这段代码被设计用于 jQuery v1.10.2

对于iOS 8.3中具有较高引导模态的任何HTML页面来说,这仍然是一个很大的错误。上面提出的解决方案都不起作用,在放大高模态折叠下方的任何字段后,Mobile Safari和/或WkWebView会将固定元素移动到HTML主体滚动条所在的位置,使它们与实际布局的位置不对齐。

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

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

我猜这是有效的,因为强制HTML主体的滚动高度重新对齐实际视图与iOS 8 WebView期望固定模态div的内容。

如果有人正在寻找一个完全不同的路线(就像你甚至不希望在滚动时固定这个"footer"div,但你只想让div留在页面底部),你可以将footer位置设置为相对位置。

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

显然,它看起来更好的Safari如果位置是固定的,页脚跟着页面,当你向上或向下滚动,但由于这个奇怪的错误在Chrome浏览器上,我们最终切换到只是使页脚相对。

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

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

iOS9 -同样的问题

TLDR -问题的来源。对于解决方案,滚动到底部

我有一个窗体在position:fixed iframe id='subscribe-popup-frame'

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

同样的问题没有发生在safari开发模式与用户代理设置为一个设备。所以问题似乎是由iOS虚拟键盘引起的,当它弹出时。

我通过控制台记录iframe的位置(例如$('#subscribe-popup-frame', window.parent.document).position())得到了一些可见性,从那里我可以看到iOS似乎在虚拟键盘弹出时将元素的位置设置为{top: -x, left: 0}(即专注于输入元素)。

所以我的解决方案是采取讨厌的-x,反转的标志,然后使用jQuery添加top的位置回到iframe。如果有更好的解决方案,我很乐意听到,但在尝试了十几种不同的方法后,这是唯一一个对我有效的。

缺点:我需要设置一个500ms的超时(也许更少的时间可以工作,但我想要安全),以确保我在iOS对元素的位置进行了恶作剧之后捕获最终的x值。因此,体验非常不稳定……但至少它有效

<<p> 解决方案/strong>
        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(){})

最新更新