【问题标题】:How do I stop my fixed navigation from moving like this when the virtual keyboard opens in Mobile Safari?当虚拟键盘在 Mobile Safari 中打开时,如何阻止我的固定导航像这样移动?
【发布时间】:2013-03-07 13:58:43
【问题描述】:

我知道移动 Safari 有很多关于固定元素的错误,但在大多数情况下,我已经设法让我的布局正常工作,直到我在底部的固定导航中添加了非常需要的文本输入。现在,当用户关注文本输入元素并出现虚拟键盘时,我的导航(原本总是固定在页面底部)会跳到页面中间一个非常奇怪的位置。

我会在这篇文章中添加一些我的代码,但我不确定从哪里开始。该导航固定在底部并位于左侧和底部 0 处,宽度为 100%。从那里,我不知道发生了什么,我只能假设它是一个移动 safari 错误。

它似乎也失去了它的固定位置并变得相对,只有在文本输入元素被聚焦并且虚拟键盘打开时。

【问题讨论】:

  • @albertxing 我刚刚做了,没有运气。这与移动 Safari 或 IOS 相关。无论出于何种原因,它会在键盘退出时移除固定位置,然后一旦键盘关闭,一切都会恢复到正常位置和属性。这也是为什么它会像这样向上移动固定元素的原因。
  • 会添加任何样式,例如margin-toptopbottom,对:active:focus 伪元素有用吗?
  • @albertxing 添加一个 215px 的负边距底部,这是它被推高的高度,是我尝试的最后一件事,但还是没有运气。
  • 好吧,我猜这可能是一个 Safari 错误。除了等待Apple修复它之外,我没有别的办法。编辑:你试过bottom: -215px吗?
  • 几个 SO 问题可能重复。详情请见gist.github.com/avesus/…

标签: ios css mobile position mobile-safari


【解决方案1】:

http://dansajin.com/2012/12/07/fix-position-fixed/ 这是建议的解决方案之一。似乎值得一试。

简而言之:当任何输入为focused 时将fixed 元素设置为position:absolute,并在该元素为blurred 时重置它们

.header { 
    position: fixed; 
} 
.footer { 
    position: fixed; 
} 
.fixfixed .header, 
.fixfixed .footer { 
    position: absolute; 
} 

if ('ontouchstart' in window) {
    /* cache dom references */ 
    var $body = $('body'); 

    /* bind events */
    $(document)
    .on('focus', 'input', function() {
        $body.addClass('fixfixed');
    })
    .on('blur', 'input', function() {
        $body.removeClass('fixfixed');
    });
}

【讨论】:

  • 啊,这是一个简单而聪明的技巧。感谢分享,为我工作。
  • Dan Sajin 网站不处理 IOS 设备上 Chrome 浏览器中的问题。但它对 Safari 非常有效。
  • 我也在尝试在聚焦文本字段时修复标题,但我们没有解决问题
【解决方案2】:

顶部的解决方案是解决问题的一些方法,但我认为添加额外的 css 类或使用 moderniz 会使事情复杂化。

如果您想要更简单的解决方案,这里有一个non-modernizr non-extra-css 但纯 jquery 解决方案 并且适用于我在所有项目中使用此修复程序的所有设备和浏览器 p>

if ('ontouchstart' in window) {
    $(document).on('focus', 'textarea,input,select', function() {
        $('.navbar.navbar-fixed-top').css('position', 'absolute');
    }).on('blur', 'textarea,input,select', function() {
        $('.navbar.navbar-fixed-top').css('position', '');
    });
}

【讨论】:

  • 这是我发现的最简单的修复方法之一,它普遍适用。干得好!
  • 非常简单的固体解决方案 :) 如果你有 contenteditable div,只需将 [contenteditable] 添加到目标
  • 这可行,但每次键盘弹出时标题都会闪烁。
【解决方案3】:

我遇到了类似的问题,但我找到了一种解决方法,方法是将以下 css 类添加到输入焦点上的 body 元素,然后在取消焦点时再次将其删除:

.u-oh {
    overflow: hidden;
    height: 100%;
    width: 100%;
    position: fixed;
}

【讨论】:

  • 其他解决方案将我的页脚隐藏在键盘下方的一半并将整个屏幕滚动到最底部,但这非常有效!
  • 只是为了从概念上清除它,为什么需要height:100%;width:100%
  • 我一直在寻找解决方案,这个解决方案在我的 react 应用程序中为我工作。
【解决方案4】:

从 sylowgreen 的做法来看,关键是在输入 input 时修复 body。因此:

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

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

【讨论】:

    【解决方案5】:

    像这样添加javascript:

    $(function() {
      var $body;
      if ('ontouchstart' in window) {
        $body = $("body");
        document.addEventListener('focusin', function() {
          return $body.addClass("fixfixed");
        });
        return document.addEventListener('focusout', function() {
          $body.removeClass("fixfixed");
          return setTimeout(function() {
            return $(window).scrollLeft(0);
          }, 20);
        });
      }
    });
    

    并像这样添加类:

    .fixfixed header{ 
        position: absolute; 
    } 
    

    可以参考这篇文章:http://dansajin.com/2012/12/07/fix-position-fixed/

    【讨论】:

      【解决方案6】:

      我真的很喜欢上面的解决方案。我将它打包成一个小的 jQuery 插件,这样我就可以:

      • 设置哪个父类获取类
      • 设置适用于哪些元素(不要忘记“textarea”和“select”)。
      • 设置父类名是什么
      • 允许它被链接
      • 允许多次使用

      代码示例:

      $.fn.mobileFix = function (options) {
          var $parent = $(this),
          $fixedElements = $(options.fixedElements);
      
          $(document)
          .on('focus', options.inputElements, function(e) {
              $parent.addClass(options.addClass);
          })
          .on('blur', options.inputElements, function(e) {
              $parent.removeClass(options.addClass);
      
              // Fix for some scenarios where you need to start scrolling
              setTimeout(function() {
                  $(document).scrollTop($(document).scrollTop())
              }, 1);
          });
      
          return this; // Allowing chaining
      };
      
      // Only on touch devices
      if (Modernizr.touch) {
          $("body").mobileFix({ // Pass parent to apply to
              inputElements: "input,textarea,select", // Pass activation child elements
              addClass: "fixfixed" // Pass class name
          });
      }
      

      【讨论】:

        【解决方案7】:

        我使用这个 jQuery 脚本:

        var focus = 0;
        var yourInput = $(".yourInputClass");
        yourInput.focusin(function(){
            if(!focus) {
                yourInput.blur();
                $("html, body").scrollTop($(document).height());
                focus = 1;
            }
            if(focus) {
                yourInput.focus();
                focus = 0;
            }
        });
        

        非常适合我。

        【讨论】:

        • 这是迄今为止对我来说最接近的解决方案,其他似乎都不起作用。这个对我有用,但有时输入会停靠在底部,虚拟键盘会与它重叠。
        【解决方案8】:

        focusinfocusout 事件似乎比 focusblur 事件更适合这个问题,因为前者会冒泡到根元素。请参阅 SO 上的this answer

        我个人使用AngularJS,所以我是这样实现的:

        $window.document.body.addEventListener('focusin', function(event) {
            var element = event.target;
            var tagName = element.tagName.toLowerCase();
            if(!$rootScope.inputOverlay && (tagName === 'input' || tagName === 'textarea' || tagName === 'select')) {
                $rootScope.$apply(function() {
                    $rootScope.inputOverlay = true;
                });
            }
        });
        $window.document.body.addEventListener('focusout', function() {
            if($rootScope.inputOverlay) {
                $rootScope.$apply(function() {
                    $rootScope.inputOverlay = false;
                });
            }
        });
        

        注意:如果这是移动版 Safari,我将有条件地运行此脚本。

        我在导航栏上放了一个ng-class 属性:

        <div class="navbar navbar-default navbar-fixed-top" ng-class="{'navbar-absolute': inputOverlay}">
        

        使用以下 CSS:

        .navbar-absolute {
            position: absolute !important;
        }
        

        你可以阅读更多关于focusinherefocusouthere的信息。

        【讨论】:

          【解决方案9】:

          测试这个。有用。我只是测试一下。

          $(document).on('focus','input', function() {
              setTimeout(function() {
                  $('#footer1').css('position', 'absolute');
                  $('#header1').css('position', 'absolute');
              }, 0);
          });
          $(document).on('blur','input', function() {
              setTimeout(function() {
                  $('#footer1').css('position', 'fixed');
                  $('#header1').css('position', 'fixed');
              }, 800);
          });
          

          【讨论】:

            【解决方案10】:

            这些解决方案都不适合我,因为我的 DOM 很复杂,而且我有动态无限滚动页面,所以我必须自己创建。

            背景:我正在使用一个固定的标题和一个更向下的元素,一旦用户向下滚动那么远,它就会粘在它下面。该元素有一个搜索输入字段。此外,我在向前和向后滚动期间添加了动态页面。

            问题:在 iOS 中,只要用户点击固定元素中的输入,浏览器就会一直滚动到页面顶部。这不仅导致了不良行为,还触发了我在页面顶部添加动态页面。

            预期的解决方案:当用户点击粘性元素中的输入时,iOS 中没有滚动(根本没有)。

            解决方案:

                 /*Returns a function, that, as long as it continues to be invoked, will not
                be triggered. The function will be called after it stops being called for
                N milliseconds. If `immediate` is passed, trigger the function on the
                leading edge, instead of the trailing.*/
                function debounce(func, wait, immediate) {
                    var timeout;
                    return function () {
                        var context = this, args = arguments;
                        var later = function () {
                            timeout = null;
                            if (!immediate) func.apply(context, args);
                        };
                        var callNow = immediate && !timeout;
                        clearTimeout(timeout);
                        timeout = setTimeout(later, wait);
                        if (callNow) func.apply(context, args);
                    };
                };
            
                 function is_iOS() {
                    var iDevices = [
                      'iPad Simulator',
                      'iPhone Simulator',
                      'iPod Simulator',
                      'iPad',
                      'iPhone',
                      'iPod'
                    ];
                    while (iDevices.length) {
                        if (navigator.platform === iDevices.pop()) { return true; }
                    }
                    return false;
                }
            
                $(document).on("scrollstop", debounce(function () {
                    //console.log("Stopped scrolling!");
                    if (is_iOS()) {
                        var yScrollPos = $(document).scrollTop();
                        if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
                            $('#searchBarDiv').css('position', 'absolute');
                            $('#searchBarDiv').css('top', yScrollPos + 50 + 'px'); //50 for fixed header
                        }
                        else {
                            $('#searchBarDiv').css('position', 'inherit');
                        }
                    }
                },250,true));
            
                $(document).on("scrollstart", debounce(function () {
                    //console.log("Started scrolling!");
                    if (is_iOS()) {
                        var yScrollPos = $(document).scrollTop();
                        if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
                            $('#searchBarDiv').css('position', 'fixed');
                            $('#searchBarDiv').css('width', '100%');
                            $('#searchBarDiv').css('top', '50px'); //50 for fixed header
                        }
                    }
                },250,true));
            

            要求:启动滚动和停止滚动功能需要 JQuery mobile。

            包含去抖动以消除粘性元素造成的任何延迟。

            在 iOS10 中测试。

            【讨论】:

              【解决方案11】:

              我对 Dan Sajin 提出的解决方案没有任何帮助。也许自从他写了那篇博文后这个 bug 已经改变了,但是在 iOS 7.1 上,当输入模糊后位置变回固定时,这个 bug 总是会出现,即使你延迟到软件键盘完全隐藏。我提出的解决方案是等待touchstart 事件而不是blur 事件,因为当页面滚动时,固定元素总是快速回到正确的位置。

              if (Modernizr.touch) {
                var $el, focused;
                $el = $('body');
                focused = false;
                $(document).on('focus', 'input, textarea, select', function() {
                  focused = true;
                  $el.addClass('u-fixedFix');
                }).on('touchstart', 'input, textarea, select', function() {
                  // always execute this function after the `focus` handler:
                  setTimeout(function() {
                    if (focused) {
                      return $el.removeClass('u-fixedFix');
                    }
                  }, 1);
                });
              }
              

              HTH

              【讨论】:

              • u-fixedFix 类包含什么css?到目前为止,这不适用于我的 iPad(在 iOS 7.1.2 - 11D257 上)。
              • 与 wxy112233 在答案中使用的类相同的规则,即。 position: absolute.
              猜你喜欢
              • 1970-01-01
              • 2018-05-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-09-15
              • 1970-01-01
              • 2012-10-17
              • 1970-01-01
              相关资源
              最近更新 更多