如何在移动Safari中打开虚拟键盘时阻止固定导航移动?
我知道移动Safari浏览器在固定的元素周围有很多的错误,但是大部分时间我都设法正确地工作,直到我在底部的固定导航中添加了一个非常需要的文本input。 现在,当用户关注文本input元素并出现虚拟键盘时,我的导航一直固定在页面的底部,在页面中间跳到一个非常奇怪的地方。
我会添加一些我的代码到这个职位,但我不知道从哪里开始。 该导航固定在底部,并定位在左侧和底部0,宽度为100%。 从那里,我不知道发生了什么,我只能认为这是一个移动的Safari浏览器的错误。
它也似乎失去了它的位置固定,并成为相对的,只有当文本input元素的重点和虚拟键盘打开。
http://dansajin.com/2012/12/07/fix-position-fixed/这是提出的解决scheme之一。; 似乎值得一试。
简而言之:将任何inputfocus
fixed
元素设置为position:absolute
,当元素blur
红色时将其重置
.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'); }); }
顶部的解决scheme是一些方法去解决这个问题,但我认为增加额外的CSS类或使用moderniz我们正在复杂的事情。
如果你想要一个更简单的解决scheme,这里是一个非现代化的 非额外的CSS,但纯粹的jQuery解决scheme,并在每个设备和浏览器上工作,我在我的所有项目
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', ''); }); }
我有一个类似的问题,但我发现一个解决方法,通过将下面的css类添加到input焦点上的body元素,然后再将其重新删除:
.u-oh { overflow: hidden; height: 100%; width: 100%; position: fixed; }
从sylowgreen所做的事情来看,关键是要固定body
进入input
。 从而:
$("#myInput").on("focus", function () { $("body").css("position", "fixed"); }); $("#myInput").on("blur", function () { $("body").css("position", "static"); });
像这样添加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/
我真的很喜欢上面的解决scheme。 我把它打包成一个小的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 }); }
我使用这个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; } });
为我完美的作品。
focusin
和focusout
事件似乎更适合于这个问题,而不是focus
和blur
事件,因为前一个泡沫直到根本元素。 在SO上看到这个答案 。
我个人使用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; }
你可以在这里阅读更多关于focusin
信息
testing这一个。 有用。 我只是testing它。
$(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); });
这些解决scheme都没有为我工作,因为我的DOM是复杂的,我有dynamic的无限滚动页面,所以我必须创build自己的。
背景:我使用一个固定的标题和一个下面的元素,一旦用户向下滚动,就会粘在它下面。 这个元素有一个searchinput字段。 另外,在向前和向后滚动时添加了dynamic页面。
问题:在iOS中,只要用户点击了固定元素中的input,浏览器就会一直滚动到页面的顶部。 这不仅造成了不良的行为,还触发了页面顶部的dynamic页面添加。
预期的解决scheme:当用户点击sticky元素中的input时,在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是startsroll和stopscroll函数工作所必需的。
反弹是为了消除由粘滞元素产生的任何滞后。
在iOS10中testing
丹萨津提出的解决scheme,我没有什么运气。 自从他写博客文章以来,这个bug可能已经发生了变化,但是在iOS 7.1上,当input模糊后,当位置变回原来的位置时,即使延迟到软件键盘完全隐藏,也会出现bug。 我遇到的解决scheme涉及到等待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