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.

enter image description here

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.

45
demandé sur Eric 2013-03-07 17:58:43

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 fixedposition:absolute lors de toute entrée est focused, et les réinitialiser lorsque cet élément est blurrouge

.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');
    });
}
18
répondu Sujesh Arukil 2015-08-14 20:50:45

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', '');
    });
}
16
répondu revobtz 2015-08-14 20:52:34

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;
}
6
répondu sylowgreen 2015-08-24 01:34:49

à 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");
});
3
répondu Scott Semyan 2016-03-22 04:22:02

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/

2
répondu wxy112233 2015-08-14 20:53:48

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
    });
}
1
répondu martinedwards 2013-11-19 11:15:10

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.

1
répondu Edie Johnny 2015-03-22 21:28:17

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

vous pouvez en savoir plus sur focusinici et focusoutici.

1
répondu brain_bacon 2017-05-23 11:46:37

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);
});
0
répondu Hesam 2016-03-22 10:22:05

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.

0
répondu Dima 2016-12-01 19:12:57

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

-1
répondu Patrick Canfield 2014-08-11 21:54:48