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'ajoute une entrée de texte bien nécessaire à la navigation fixe en bas. Maintenant, lorsque l'utilisateur se concentre sur l'élément de saisie de texte 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'ajouterais une partie de mon code à cet article, mais je ne sais pas par où commencer. Cette navigation est fixée en bas et positionnée à gauche et en bas 0, et 100% de largeur. De là, je ne sais pas ce qui se passe, je peux seulement supposer que c'est un bug de safari mobile.
Il semble également perdre sa position fixe et devenir relatif, uniquement lorsque l'élément de saisie de texte est concentré et que le clavier virtuel est ouvert.
http://dansajin.com/2012/12/07/fix-position-fixed/ c'est l'une des solutions proposées. Semble valoir un coup.
En bref: définissez les éléments fixed
sur position:absolute
lorsqu'une entrée est focus
ed et les réinitialiser lorsque cet élément est blur
red
.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 résoudre le problème, mais je pense que l'ajout de classe CSS supplémentaire ou l'utilisation de moderniz complique les choses.
Si vous voulez une solution plus simple, voici une non-modernizrnon-extra-css mais pure solution jquery et travailler sur tous les appareils et navigateurs J'utilise 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 de contournement en ajoutant la classe css suivante à l'élément body sur le focus d'entrée, puis en le supprimant à nouveau sur flou:
.u-oh {
overflow: hidden;
height: 100%;
width: 100%;
position: fixed;
}
À partir de ce qu'a fait sylowgreen, la clé est de corriger le body
en entrant le input
. Ainsi:
$("#myInput").on("focus", function () {
$("body").css("position", "fixed");
});
$("#myInput").on("blur", function () {
$("body").css("position", "static");
});
Ajoutez du 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 ajoutez une classe comme celle-ci:
.fixfixed header{
position: absolute;
}
vous pouvez référencer cet article: http://dansajin.com/2012/12/07/fix-position-fixed/
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.
Les événements focusin
et focusout
semblent mieux adaptés à ce problème que les événements focus
et blur
depuis l'ancienne bulle jusqu'à l'élément racine. Voir cette réponse sur SO.
Personnellement, j'utilise AngularJS, donc je l'ai implémenté 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 conditionnellement ce script s'il s'agit de Safari mobile.
Je mets un ng-class
attribut sur ma barre de navigation:
<div class="navbar navbar-default navbar-fixed-top" ng-class="{'navbar-absolute': inputOverlay}">
en utilisant le CSS suivant:
.navbar-absolute {
position: absolute !important;
}
J'aime vraiment la solution ci-dessus. Je l'ai emballé dans un petit plugin jQuery pour que je puisse:
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
});
}
Aucune de ces solutions n'a fonctionné pour moi car mon DOM est compliqué et j'ai des pages de défilement infinies dynamiques, j'ai donc dû créer les vôtres.
Background: J'utilise un en-tête fixe et un élément plus bas qui reste en dessous une fois que l'utilisateur fait défiler aussi bas. Cet élément possède un champ de saisie de recherche. De plus, j'ai des pages dynamiques ajoutées pendant le défilement avant et arrière.
Problème: Dans iOS, à chaque fois que l'utilisateur clique sur l'entrée dans l'élément fixe, le navigateur défile jusqu'en haut de la page. Cela a non seulement causé un comportement indésirable, mais a également déclenché mon ajout de page dynamique en haut de la page.
Solution attendue: Pas de défilement dans iOS (pas du tout) lorsque l'utilisateur clique sur l'entrée dans l'élément collant.
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 requis pour que les fonctions de démarrage et d'arrêt fonctionnent.
La fonction anti-rebond est incluse pour lisser tout décalage créé par l'élément collant.
Testé sur iOS10.
Testez celui-ci. Ça marche. 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);
});