web-dev-qa-db-fra.com

iOS 7 Safari: le système d'exploitation se bloque pendant 4 secondes lorsque vous cliquez/effectuez une mise au point sur une entrée HTML

MISE À JOUR: Le problème semble provenir de nombreux éléments sélectionnés sur une page. Comment est-ce aléatoire?

Alors voici le problème. Sur iOS 7 Safari, lorsque vous appuyez sur l'entrée de texte sur mon site, le clavier s'ouvre, puis gèle le système d'exploitation pendant environ 2 à 5 secondes, puis fait défiler jusqu'à l'entrée. Une fois que cela se produit une fois, cela ne se reproduira plus tant que vous n'aurez pas actualisé la page. J'ai regardé partout, et oui, iOS 7 Safari est un super buggy, mais essayons de voir si nous pouvons résoudre ce problème. 

Remarque: cela ne se produit dans aucun autre navigateur mobile ni dans aucun ancien iOS Safari. Cela se produit à la fois sur l'iPhone iOS 7 et l'iPad iOS 7.

Je vais énumérer tout ce que mon ami et moi avons essayé jusqu'à présent:

  • Suppression de la possibilité d'ajouter des gestionnaires d'événements dans jQuery. (Remarque: tous nos gestionnaires d'événements sont attribués via jQuery, à l'exception de déchargement et onpageshow).
  • Suppression du script de saisie semi-automatique jQuery des entrées.
  • Suppression de tout le JavaScript des entrées.
  • Suppression de toutes les bibliothèques tierces ajoutées à la page en rejetant les domaines sur le Mac.
  • Retour aux versions précédentes de jQuery. Le dernier que nous pouvions réellement utiliser avant que rien ne fonctionne est 1.7.0.
  • Revenez aux versions précédentes de l'interface utilisateur jQuery.
  • Modification de la gestion des événements d'entrée en délégation et en direct, au lieu de (cliquer)
  • Suppression de toutes les classes CSS.
  • Suppression de tous les CSS de la page. Remarque: le temps de réponse pour le système d'exploitation s'est abaissé à 1-2 secondes, mais s'est toujours produit.

Quelqu'un a-t-il une idée?

Merci beaucoup!

38
transformerTroy

(Il existe des solutions quelque peu efficaces, voir vers la fin de la liste)

Chez nous, nous en souffrons également. Nous avons déposé un problème avec Apple, mais avons entendu maman.

Voici quelques astuces intéressantes pour vous aider à illustrer certains problèmes. Il semble bien que cela tourne autour du nombre de champs cachés et que les zones de texte ne semblent pas être affectées.

D'après les efforts de débogage, je suppose que certaines fonctionnalités tentent de détecter si une entrée est une carte de crédit, un numéro de téléphone ou un type spécial qui semble provoquer le comportement de verrouillage. Ceci n’est cependant qu’une hypothèse ..

Résumé:

Sur une page comportant un formulaire contenant des éléments d’entrée nommés dans des conteneurs portant la mention "display: none", la première pression sur une entrée de ce formulaire présente un délai très perceptible (20 s-2 min) entre le déclenchement du clavier et la mise au point de l’entrée. . Cela empêche les utilisateurs d’utiliser notre application Web en raison du temps considérable passé avec l’interface utilisateur gelée à attendre que le clavier réponde. Nous l'avons débogué dans différents scénarios pour essayer de discerner ce qui se passait, et il semble s'agir d'un changement dans la façon dont iOS7 analyse le DOM par rapport à son fonctionnement sur iOS6, qui ne présente aucun de ces problèmes. 

Depuis le débogage dans l'inspecteur de Safari avec l'iPad connecté, nous avons constaté qu'iOS7 fournit beaucoup plus d'informations sur les activités du (programme), à ​​tel point que nous avons constaté que _CollectFormMetaData est le parent du problème. La recherche de métadonnées provoque un taux de désabonnement massif qui augmente plus que linéairement, ainsi que le nombre de conteneurs cachés contenant des entrées. Nous avons constaté que _isVisible et _isRenderedFormElement sont appelés beaucoup plus qu'ils ne devraient normalement l'être. De plus, si cela vous aide, nous avons constaté que certaines fonctions de détection relatives aux cartes de crédit et aux carnets d’adresses étaient de grands consommateurs de temps.

Voici quelques exemples de jsFiddles. Veuillez les afficher dans Safari sur un iPad sous iOS6, puis sur un iPad sous iOS7:

http://jsfiddle.net/gUDvL/20/ - Fonctionne bien sur les deux

http://jsfiddle.net/gUDvL/21/ - Un retard perceptible sur iOS 7

http://jsfiddle.net/gUDvL/22/ - Retard plus visible sur iOS 7

http://jsfiddle.net/gUDvL/29/ - Retard très visible sur iOS 7

http://jsfiddle.net/gUDvL/30/ - Identique à 29 mais non masqué - aucun délai sur iOS 7

http://jsfiddle.net/gUDvL/38/ - Identique à 29 mais exacerbé

http://jsfiddle.net/gUDvL/39/ - 99 entrées cachées, une visible, une visible séparément

http://jsfiddle.net/gUDvL/40/ - 99 zones de texte masquées, une visible, une visible séparément

http://jsfiddle.net/gUDvL/41/ - 99 entrées masquées, une visible, une visible séparément, toutes .__ avec l'attribut autocomplete = "off"

http://jsfiddle.net/gUDvL/42/ - 99 entrées cachées, une visible, une visible séparément. Caché par la position absolue et gauche au lieu de l'affichage.

http://jsfiddle.net/gUDvL/63/ - Identique à gUDvL/43/mais avec autocomplete, autocorrect, autocapitalize et correction orthographique

http://jsfiddle.net/gUDvL/65/ - Identique à gUDvL/63/mais avec une mise en retrait nettoyée (semble plus lent sur iPad)

http://jsfiddle.net/gUDvL/66/ - Identique à gUDvL/65/mais avec aucun affichage via css à la place de DOMReady jQuery

http://jsfiddle.net/gUDvL/67/ - Identique à gUDvL/66/mais avec la technique de mise au point/flou de TedGrav

http://jsfiddle.net/gUDvL/68/ - Identique à gUDvL/66/mais avec l'indentation textuelle basée sur css au lieu de display: block again (amélioration notable - réduction à 2-3 secondes pour la première fois concentrer)

http://jsfiddle.net/gUDvL/69/ - Identique à gUDvL/68/mais avec le focus/flou de TedGrav ajouté

http://jsfiddle.net/gUDvL/71/ - Identique à gUDvL/66/mais js ajoute une balise de légende avant chaque entrée. (amélioration notable - réduction à 2-3 secondes pour la mise au point initiale)

<input type="text" autocomplete="off" /> (links to jsfiddle.net must be accompanied by code..)

(Notons que le fait de connecter l’iPad à un Mac avec le débogueur de Safari activé accentue considérablement les retards.)

Etapes pour reproduire:

  1. Chargez n'importe lequel des jsfiddles ci-dessus sur l'iPad
  2. Appuyez sur une entrée pour obtenir le focus
  3. Regardez l'écran jusqu'à ce que vous puissiez taper

Résultats attendus:

Attendez-vous à pouvoir taper dès que le clavier apparaît

Résultats actuels:

Regardez le clavier apparaître et l'écran se figer, incapable de faire défiler ou d'interagir avec Safari pendant un certain temps. Après la durée, l'accent est donné comme prévu. À partir de ce moment-là, on ne gèle plus lorsqu'on se concentre sur les entrées.

tl; dr résumé technique

Donc dans l’ensemble, il existe quelques correctifs proposés à partir de diverses réponses:

  • Ne cache pas les divs avec display: none - utilise quelque chose comme text-indent
  • Court-circuitez la logique d'analyse des métadonnées d'Apple - de nombreuses balises de formulaire ou de légende semblent faire l'affaire
  • Mise au point automatique/Flou - N'a pas fonctionné pour moi, mais deux personnes ont signalé le contraire.

Fils associés chez Apple:

https://discussions.Apple.com/thread/5468360

13
Jasmine Hegman

Il semble y avoir un problème avec la façon dont IOS gère l'événement touch- pour les entrées et les zones de texte. Le délai augmente lorsque le DOM augmente. Il n'y a cependant pas de problème avec l'événement focus!

Pour contourner ce problème, vous pouvez remplacer l'événement touchend et définir le focus sur l'entrée/zone de texte.

document.addEventListener("touchend", function (e) {  
     if (e.target.nodeName.toString().toUpperCase() == 'INPUT' || e.target.nodeName.toString().toUpperCase() == 'TEXTAREA') {  
         e.preventDefault(); 
         e.target.focus(); 
     } 
});

Cela créera toutefois un nouveau problème. Il vous permettra de faire défiler la page tout en touchant l’entrée/zone de texte, mais lorsque vous lâchez le bouton, le site revient à la position initiale.

Pour résoudre ce problème, il vous suffit de vérifier si un défilement a déjà eu lieu et d’entourer les instructions preventDefault et target.focus avec une instruction if.

Pour définir la position d'origine, vous pouvez utiliser l'événement touchstart .

document.addEventListener("touchstart", function (e) {
    ... //store the scrollTop or offsetHeight position and compare it in touchend event.
}

EDITMoi et un collègue l’avons un peu améliorée, et cela fonctionne à merveille.

var scroll = 0; 
document.addEventListener("touchstart", function (e) { 
    scroll = document.body.scrollTop; 
 });   

document.addEventListener("touchend", function (e) { 
    if (scroll == document.body.scrollTop) { 
        var node = e.target.nodeName.toString().toUpperCase(); 
        if (node == 'INPUT' || node == 'TEXTAREA' || node == 'SELECT') { 
            e.preventDefault(); 
            e.target.focus(); 
            if(node != 'SELECT') {
                var textLength = e.target.value.length; 
                e.target.setSelectionRange(textLength, textLength);
            }
        } 
    } 
}); 
7
Binke

Lutté avec ce problème également dans un plein écran ios qui insérait/supprimait des pages contenant un seul élément d’entrée. Retards pouvant atteindre 30 secondes avec un seul élément de saisie de texte visible sur la page (et dans l'ensemble du DOM). D'autres pages insérées dynamiquement avec une ou plusieurs entrées de texte dans la même application Web ne rencontraient pas le délai d'entrée. Comme d'autres l'ont mentionné, après le délai initial, le champ d'entrée se comporterait normalement lors d'événements de focus ultérieurs (même si la page dynamique contenant l'élément d'entrée était supprimée du DOM, puis restituée/insérée dynamiquement dans le DOM).

Sur un pressentiment basé sur le comportement ci-dessus, essayez ce qui suit au chargement de la page:

$ ("# problème-entrée"). focus (); $ ("# problème-entrée"). blur ();

Bien que ce qui précède s’exécute immédiatement et sans délai, le résultat final n’est aucun retard ultérieur lorsque l’entrée obtient le focus via l’interaction de l’utilisateur. Je ne peux pas expliquer la raison de ce fonctionnement, mais cela semble fonctionner de manière cohérente pour mon application, alors que les autres solutions suggérées ont échoué.

3
TedGrav

Le problème principal pour moi était avec les champs cachés. Fait suspendre le formulaire pendant 10-15 secondes.

J'ai réussi à me déplacer en positionnant les champs de formulaire masqués hors de l'écran.


Cacher:

position: absolute;
left: -9999px;

Montrer:

position: relative;
left: 0;

3
Simon McFarlane

J'ai le même problème freezeing.

Je ne suis pas sûr que nous sommes dans la même situation.

voici ma démo: http://tedzhou.github.io/demo/ios7sucks.html

Dans ma page, j'utilise un élément <p> avec l'attribut onclick comme un bouton . Lorsque l'utilisateur clique sur le bouton , la page devient une textarea. Un clic sur ce bouton se bloque le navigateur.

Le temps de gel passé en relation avec les nombres des éléments dom . Dans mes pages, il y a 10000 éléments, ce qui le gèle de plus de 10 secondes.

Nous pouvons résoudre le problème en remplaçant l'élément <p> par le <button> réel ou en réduisant le nombre d'éléments dom.

ps: désolé pour mon anglais médiocre. LOL

3
tedzhou

Pour moi, ce problème était dû au fait que les entrées utilisateur étaient masquées sur la page avec display:none.

La solution que j'ai utilisée: au lieu de masquer les entrées avec display:none, j'ai utilisé la méthode detach() de jQuery sur un document prêt à "masquer" toutes les entrées utilisateur non utilisées. Puis append() les entrées quand elles étaient nécessaires.

De cette façon, aucune entrée ne contenait display:none lors du premier chargement de la page et aucun délai ne s'est donc produit lors de l'interaction initiale de l'utilisateur.

1
Dan Bamber

Cela se produit non seulement dans iOS, mais également dans le safari 7 pour MAC OS (Maverics). J'ai également constaté que le problème se produisait lorsque vous utilisiez beaucoup de balises div pour contenir des entrées (ou sélections) dans un formulaire:

<div> <select>...</select> </div>
<div> <select>...</select> </div>
...

J'ai changé la disposition de mes sélections pour utiliser ul/li et fieldsets au lieu de divs et le temps de refroidissement a été considérablement réduit.

<ul>
   <li><select>...</select></div>
   <li><select>...</select></div>
</ul>

Voici deux exemples dans jsfiddle:

congeler pendant 5 secondes

http://jsfiddle.net/k3j5v/5/

congeler pendant 1 seconde

http://jsfiddle.net/k3j5v/6/

J'espère que ça pourrait aider quelqu'un

1
Raphael Isidro

A rencontré le même problème dans une application assez complexe comportant de nombreuses entrées. 

Attachement du débogueur à Safari iOS7 via USB et événements enregistrés de l'interface utilisateur. Je vois un événement "touchend" dès que je clique sur textarea (ou sur une entrée) et dans 10 à 20 secondes après que je vois un "clic" envoyé. 

Il s'agit clairement d'un bogue dans Safary, car sur d'autres appareils comme Android ou iOS6, la même application ne pose aucun problème.

1
c-smile

Ma réponse pourrait être légèrement différente du sujet principal, mais je suis arrivée ici après quelques recherches, car le scénario "semble" être similaire.

Problème:

Mon problème ressemblait à un blocage dans iOS, mais pas tout à fait, car d'autres éléments de la page étaient toujours interactifs. J'avais un élément <input type="search" /> qui ne se focalisait pas lorsque je cliquais dans le champ. Mais il finirait bien par se focaliser après environ 4-5 tapotements sur l'écran.

Information additionnelle:

Mon projet est une application hybride: WebView dans une application iOS. Le site est construit avec Twitter Bootstrap.

Solution:

Il m'est également arrivé d'avoir l'attribut autofocus défini sur l'élément. J'ai essayé de supprimer ça et ça a fonctionné ... plus de tapotements consécutifs pour que le champ se concentre.

0
EdwardM

J'ai rencontré ce problème aussi car j'ai remarqué que beaucoup de gens ont toujours un problème avec ça, j'ai pensé mettre ma solution.

Fondamentalement, ma solution consiste à masquer des éléments côté serveur. Ma page est ASP.NET alors j’enveloppai mes divs avec les entrées avec Panels et configurai ces panneaux comme étant Visible false . Ainsi, si je clique sur une entrée, le safari ne peut pas voir tous les autres contrôles car ils sont cachés côté serveur.

Bien sûr, si vous voulez que cela fonctionne un peu comme jquery côté client, vous aurez besoin d’une publication automatique et d’un panneau de mise à jour quelque part .. Cette solution nécessite un effort, mais elle vaut mieux que de tenter réellement de réparer un bogue Safari.

J'espère que cela t'aides.

0
misha130

iOS 12.1.1 - Décembre 2018

Voici une solution simple qui a fonctionné dans mon cas:

window.scrollTo(0,0) // attaché à l'événement 'blur' pour les champs de saisie

Bien que cela puisse ne pas être idéal en termes d'utilisation de l'expérience utilisateur (en particulier si vous avez un formulaire avec de nombreux champs), c'est certainement mieux que d'avoir 10 secondes de temps de congélation.

0
SC1000

Nous avons eu le même problème ou un problème similaire dans mon entreprise. Chaque fois que nous affichions un grand nombre de listes déroulantes et qu'un utilisateur cliquait dessus, IOS 7 gelait la page pendant une minute ou deux. Après le dégel, tout fonctionnerait correctement à partir de ce moment. 

Cela a affecté tous les types d'entrée. Le grand nombre de listes déroulantes était en fait masqué lors du premier chargement: l'utilisateur initialisait l'affichage des listes déroulantes. Jusqu'à ce que les menus déroulants soient affichés - tout fonctionnerait bien. Dès qu’ils étaient affichés, le prochain clic d’entrée, même une entrée qui fonctionnait correctement, entraînait le blocage du navigateur.

Comme d'autres l'ont noté, il semble que IOS 7 présente un problème lors de l'analyse syntaxique des entrées visibles dans le DOM après la première interaction de l'utilisateur avec une entrée. Lorsque le nombre et/ou la complexité des éléments/options/DOM sont plus élevés, le gel est plus prononcé.

Etant donné que l'interaction utilisateur initiale était toujours figée, nous avons décidé de lancer une action utilisateur masquée dès que nous avons affiché la liste des menus déroulants. Nous avons créé un bouton transparent (il ne pouvait pas être masqué - il devait être "affiché") et avons cliqué dessus dès que l'utilisateur a ouvert la liste déroulante. Nous pensions que cela ferait IOS commencer à analyser le DOM plus rapidement, mais nous avons constaté que le problème était complètement résolu. 

0
Henry Fieger