CSS 当虚拟键盘在 Mobile Safari 中打开时,如何阻止固定导航像这样移动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15273098/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 21:56:29  来源:igfitidea点击:

How do I stop my fixed navigation from moving like this when the virtual keyboard opens in Mobile Safari?

ioscssmobilepositionmobile-safari

提问by Eric

I understand that mobile safari has a lot of bugs around fixed elements, but for the most part I've managed to get my layout working correctly until I added a much needed text input to the fixed navigation at the bottom. Now when the user focuses on the text input element and the virtual keyboard appears, my navigation, which is otherwise always fixed at the bottom of the page, jumps up to a really strange spot in the middle of the page.

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

enter image description here

在此处输入图片说明

I'd add some of my code to this post, but I wouldn't be sure where to start. That navigation is fixed at the bottom and positioned to the left and bottom 0, and 100% width. From there, I don't know what's going on, I can only assume it's a mobile safari bug.

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

It also appears to lose it's position fixed and become relative, only while the text input element is focused on and the virtual keyboard is open.

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

回答by Sujesh Arukil

http://dansajin.com/2012/12/07/fix-position-fixed/this is one of the solutions proposed. Seems worth a shot.

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

In short: set fixedelements to position:absolutewhen any input is focused and reset them when that element is blurred

简而言之:在任何输入被编辑时设置fixed元素并在该元素为红色时重置它们position:absolutefocusblur

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

and

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

回答by revobtz

The solutions on the top are some ways to go and fix the problem, but I think adding extra css class or using moderniz we are complicating things.

If you want a more simple solution, here is a non-modernizrnon-extra-cssbut pure jquery solutionand work on every device and browsers I use this fix on all my projects

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

如果你想要一个更简单的解决方案,这里有一个非现代非额外 css但纯jquery 解决方案,适用于所有设备和浏览器,我在我所有的项目中都使用了这个修复程序

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

回答by sylowgreen

I had a similar problem, but I found a workaround by adding the following css class to the body element on input focus and then removing it again on unfocus:

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

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

回答by Scott Semyan

Taking from what sylowgreen did, the key is to fix the bodyon entering the input. Thus:

根据 sylowgreen 所做的,关键是修复body进入input. 因此:

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

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

回答by wxy112233

Add javascript like this:

像这样添加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);
    });
  }
});

and add class like this:

并添加这样的类:

.fixfixed header{ 
    position: absolute; 
} 

you can reference this article: http://dansajin.com/2012/12/07/fix-position-fixed/

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

回答by martinedwards

I really like the solution above. I packaged it up into a little jQuery plugin so I could:

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

  • Set which parent gets the class
  • Set which elements this applies to (don't forget "textarea" and "select").
  • Set what the parent class name is
  • Allow it to be chained
  • Allow it to be used multiple times
  • 设置哪个父级获得类
  • 设置这适用于哪些元素(不要忘记“textarea”和“select”)。
  • 设置父类名称是什么
  • 允许它被链接
  • 允许多次使用

Code example:

代码示例:

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

回答by brain_bacon

The focusinand focusoutevents seem to be better suited to this problem than the focusand blurevents since the former bubble up to the root element. See this answeron SO.

focusinfocusout事件似乎更适合这个问题比focusblur事件,因为前者泡沫达根元素。请参阅SO 上的此答案

Personally I use AngularJS, so I implemented it like this:

我个人使用 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;
        });
    }
});

Note:I am conditionally running this script if this is mobile Safari.

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

I put an ng-classattribute on my navbar:

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

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

using the following CSS:

使用以下 CSS:

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

You can read more about focusinhereand focusouthere.

您可以阅读更多关于focusin这里focusout这里的信息

回答by Edie Johnny

I use this jQuery script:

我使用这个 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;
    }
});

Works perfectly for me.

非常适合我。

回答by Hesam

Test this one. It works. I just test it.

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

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

回答by Dima

None of these solutions worked for me because my DOM is complicated and I have dynamic infinite scroll pages, so I had to create my own.

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

Background:I am using a fixed header and an element further down that sticks below it once the user scrolls that far down. This element has a search input field. In addition, I have dynamic pages added during forward and backwards scroll.

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

Problem:In iOS, anytime the user clicked on the input in the fixed element, the browser would scroll all the way to the top of the page. This not only caused undesired behavior, it also triggered my dynamic page add at the top of the page.

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

Expected Solution:No scroll in iOS (none at all) when the user clicks on the input in the sticky element.

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

Solution:

解决方案:

     /*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));

Requirements:JQuery mobile is required for the startsroll and stopscroll functions to work.

要求:开始滚动和停止滚动功能需要使用 JQuery 移动版。

Debounce is included to smooth out any lag created by the sticky element.

包括去抖动以消除粘性元素造成的任何滞后。

Tested in iOS10.

在iOS10中测试。