Comment puis-je empêcher ma navigation fixe de se déplacer comme cela lorsque le clavier virtuel s'ouvre dans un Safari Mobile?
je comprends que le safari mobile a beaucoup de bugs autour des éléments fixes, mais pour la plupart j'ai réussi à faire fonctionner ma mise en page correctement jusqu'à ce que j'ai ajouté une entrée de texte nécessaire à la navigation fixe en bas. Maintenant, lorsque l'utilisateur se concentre sur l'élément text input et que le clavier virtuel apparaît, ma navigation, qui est par ailleurs toujours fixée en bas de la page, saute à un endroit vraiment étrange au milieu de la page.
j'aimerais ajouter un peu de mon code pour ce post, mais je ne serais pas sûr où commencer. Cette navigation est fixée au fond et positionnée à gauche et en bas 0, et largeur de 100%. De là, Je ne sais pas ce qui se passe, Je ne peux que supposer que c'est un bug de safari mobile.
il semble aussi perdre sa position fixe et devenir relatif, seulement pendant que l'élément d'entrée de texte est concentré sur et le clavier virtuel est ouvert.
11 réponses
http://dansajin.com/2012/12/07/fix-position-fixed/ c'est l'une des solutions proposées. Semble en vaut le coup.
en bref: set fixed
position:absolute
lors de toute entrée est focus
ed, et les réinitialiser lorsque cet élément est blur
rouge
.header {
position: fixed;
}
.footer {
position: fixed;
}
.fixfixed .header,
.fixfixed .footer {
position: absolute;
}
et
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');
});
}
Les solutions sur le dessus sont quelques façons d'aller et de résoudre le problème, mais je pense que l'ajout de classe CSS supplémentaire ou l'utilisation de moderniz nous compliquent les choses.
Si vous voulez une solution plus simple, voici un non-modernizr non-extra-css mais pur jQuery solution et de travailler sur tous les appareils et navigateurs-je utiliser ce correctif sur tous mes projets
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', '');
});
}
j'ai eu un problème similaire, mais j'ai trouvé une solution en ajoutant la classe CSS suivante à l'élément body sur input focus et en la retirant à nouveau sur unfocus:
.u-oh {
overflow: hidden;
height: 100%;
width: 100%;
position: fixed;
}
à partir de ce que sylowgreen a fait, la clé est de corriger le body
en entrant le input
. Donc:
$("#myInput").on("focus", function () {
$("body").css("position", "fixed");
});
$("#myInput").on("blur", function () {
$("body").css("position", "static");
});
ajouter javascript comme ceci:
$(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);
});
}
});
et ajouter une classe comme ceci:
.fixfixed header{
position: absolute;
}
http://dansajin.com/2012/12/07/fix-position-fixed/
j'aime vraiment la solution ci-dessus. J'ai emballé le tout dans un petit plugin jQuery donc je le pouvais:
- Définir le parent qui obtient la classe
- définir les éléments auxquels cela s'applique (n'oubliez pas "textarea" et "select").
- définir le nom de la classe mère
- Permettez-lui d'être enchaîné
- permet de l'utiliser plusieurs fois
exemple de Code:
$.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
});
}
j'utilise ce 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;
}
});
Fonctionne parfaitement pour moi.
focusin
et focusout
événements semblent être les mieux adaptés à ce problème que l' focus
et blur
événements depuis l'ancienne bulle jusqu'à l'élément racine. Voir cette réponse sur.
Personnellement, je utiliser AngularJS, donc j'ai mis en place comme ceci:
$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;
});
}
});
Remarque: j'exécute ce script si C'est un Safari mobile.
j'ai mis un ng-class
l'attribut sur mon barre de navigation:
<div class="navbar navbar-default navbar-fixed-top" ng-class="{'navbar-absolute': inputOverlay}">
en utilisant le code CSS suivant:
.navbar-absolute {
position: absolute !important;
}
Tester celui-ci. Elle fonctionne. Je viens de le tester.
$(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);
});
aucune de ces solutions n'a fonctionné pour moi parce que mon DOM est compliqué et que j'ai des pages dynamiques infinies, donc j'ai dû créer la mienne.
Contexte: j'utilise un en-tête fixe et un élément plus bas qui colle au-dessous une fois que l'utilisateur se déplace aussi bas. Cet élément a un champ d'entrée de recherche. De plus, j'ai ajouté des pages dynamiques pendant le défilement vers l'avant et vers l'arrière.
Problème: dans iOS, chaque fois que l'utilisateur cliquait sur l'entrée dans l'élément fixe, le navigateur ferait défiler jusqu'au haut de la page. Cela a non seulement causé un comportement indésirable, il a aussi déclenché mon ajout de page dynamique en haut de la page.
Solution Attendue: Pas de scroll dans iOS (aucun) lorsque l'utilisateur clique sur l'entrée dans le collant élément.
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));
Exigences: JQuery mobile est nécessaire pour le startsroll et stopscroll les fonctions de travail.
anti-rebond est inclus pour lisser toute décalage créé par le collant de l'élément.
testé dans iOS10.
Je n'avais aucune chance avec la solution proposée par Dan Sajin. Peut-être que le bug a changé depuis qu'il a écrit ce billet de blog, mais sur iOS 7.1, Le bug réapparaîtra toujours lorsque la position est changée et corrigée après que l'entrée est floue, même si vous tardez jusqu'à ce que le clavier du Logiciel soit complètement caché. La solution que j'ai trouvée consiste à attendre un touchstart
événement plutôt que le blur
événement puisque l'élément fixe revient toujours dans la bonne position lorsque la page est défiler.
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