Le défilement de l'iPad Safari fait disparaître et réapparaître les éléments HTML avec un retard

165

Je développe actuellement une application Web utilisant html5 et jQuery pour iPad Safari. Je rencontre un problème dans lequel de grandes zones de défilement font apparaître les éléments hors écran après un certain temps lorsque je fais défiler vers eux.

Ce que je veux dire par là, c'est que si j'ai une rangée d'images (ou même un div avec un dégradé) qui est hors écran, lorsque je fais défiler vers le bas (ou vers le haut), le comportement attendu est que l'élément apparaisse à l'écran comme J'y fais défiler.

Cependant, ce que je vois, c'est que l'élément n'apparaît pas tant que je ne lève pas mon doigt de l'écran et que la molette de défilement termine toutes ses animations.

Cela me pose un problème très perceptible, donnant à l'ensemble un aspect saccadé, bien que ce ne soit pas le cas. J'imagine que l'iPad Safari essaie de faire quelque chose pour économiser de la mémoire. Y a-t-il un moyen pour que je puisse empêcher cette agitation de se produire. De plus, j'apprécierais également que quelqu'un puisse faire la lumière sur ce que l'iPad Safari tente réellement de faire.

codeBearer
la source
Ce problème / solution m'a aidé à résoudre un problème avec la version jPanelMenu 1.3 CSS Transforms, qui a tout transformé sur mon site invisibie jusqu'à ce que j'ajoute l'extrait ci-dessus.
75th Trombone
2
L'utilisation de *: not (html) appliquera le translate3d à tous les autres aspects de votre site et je ne le recommande pas. Cela fera disparaître les images dans les onglets lorsque vous faites défiler vers le bas, etc., les bogues que vous pourriez avoir l'habitude de voir uniquement sur vos images 3D seront désormais présents dans d'autres aspects de votre site.
Jonathan Tonge
1
J'avais quelques <svg>éléments qui présentaient un dessin / rendu retardé similaire. Malheureusement, cela a *:not(html) { ... }conduit à toutes sortes de comportements étranges, comme l'a souligné @JonathanTonge. Cependant, sélectionner uniquement les <svg>éléments et utiliser translate3d(0, 0, 0,);semble avoir résolu mes problèmes de défilement.
Zephyr Mays
Sauf pour des cas d'utilisation très spécifiques, ce sont des déchets. Vraiment gâche les dispositions qui dépendent d'éléments de position absolue.
Stoutie le
2
Veuillez publier les réponses en tant que réponses, et non «MODIFIER» dans votre question. Je sais que vous aimez mieux votre réponse, et c'est très bien, mais StackOverflow a un format de questions-réponses qui fonctionne mieux lorsque les Q sont distincts des A.
Slipp D.Thompson

Réponses:

184

Vous devez tromper le navigateur pour utiliser l'accélération matérielle plus efficacement. Vous pouvez le faire avec une transformation 3d vide:

-webkit-transform: translate3d(0,0,0)

En particulier, vous en aurez besoin sur les éléments enfants qui ont une position:relative;déclaration (ou, tout simplement, faites-le pour tous les éléments enfants).

Pas une solution garantie, mais assez réussie la plupart du temps.

Astuce du chapeau: https://web.archive.org/web/20131005175118/http://cantina.co/2012/03/06/ios-5-native-scrolling-grins-and-gothcas/

Colin Williams
la source
3
J'ai essayé ça aussi. Malheureusement, l'ajout d'un translate3d coupe les éléments qui étaient affichés correctement auparavant. J'avais également besoin d'une accélération matérielle pour quelques objets qui étaient hors écran et qui devaient être animés pour "voler" à l'écran. J'utilisais animate () de jQuery, qui était super lent. Je suis passé à l'utilisation de l'accélération matérielle. Bien que cela ait accéléré l'animation, cela a produit des résultats erratiques, dans le sens où certains des éléments enfants de la div parent (animante) ont été coupés. Cela ne se produisait pas lorsque j'utilisais animate ().
codeBearer
1
@Colin Williams tu viens de faire ma journée! : D
Luc
9
Wow, c'est horrible mais efficace. Je vous remercie.
Tim Down
1
Homme star de l'or freakin! Je l'ai ajouté à tous mes éléments li dans un div à défilement. Pouf. Travaillé.
Bryan Johnson
68

C'est la réponse complète à ma question. J'avais initialement marqué la réponse de @Colin Williams comme la bonne réponse, car cela m'a aidé à trouver la solution complète. Un membre de la communauté, @Slipp D. Thompson a édité ma question, après environ 2,5 ans que je l'ai posée, et m'a dit que j'abusais du format de questions et réponses de SO. Il m'a également dit d'afficher séparément ceci comme réponse. Voici donc la réponse complète qui a résolu mon problème:

@Colin Williams, merci! Votre réponse et l'article auquel vous avez créé un lien m'ont incité à essayer quelque chose avec CSS.

Donc, j'utilisais translate3d avant. Cela a produit des résultats indésirables. Fondamentalement, cela couperait et ne rendrait PAS les éléments qui étaient hors écran, jusqu'à ce que j'interagisse avec eux. Donc, fondamentalement, en orientation paysage, la moitié de mon site qui était hors écran n'était pas affichée. Ceci est une application Web iPad, à cause de laquelle j'étais dans un correctif.

L'application de translate3d à des éléments relativement positionnés a résolu le problème de ces éléments, mais d'autres éléments ont arrêté le rendu, une fois hors écran. Les éléments avec lesquels je ne pouvais pas interagir (illustration) ne seraient plus jamais rendus, sauf si je rechargeais la page.

La solution complète:

*:not(html) {
    -webkit-transform: translate3d(0, 0, 0);
}

Maintenant, bien que ce ne soit peut-être pas la solution la plus «efficace», c'est la seule qui fonctionne. Mobile Safari ne rend pas les éléments qui sont hors écran, ou parfois de manière erratique, lors de l'utilisation -webkit-overflow-scrolling: touch. À moins qu'un translate3d ne soit appliqué à tous les autres éléments qui pourraient sortir de l'écran en raison de ce défilement, ces éléments seront coupés après le défilement.

Alors, merci encore et j'espère que cela aidera une autre âme perdue. Cela m'a sûrement beaucoup aidé!

codeBearer
la source
2
Sensationnel. Merci pour cela. Cela m'a sauvé énormément de maux de tête pour mon application phonegap / cordova. J'ai eu dans mon cas changer *:not(html)àbody *
Anon
9
appliquer simplement -webkit-transform: translate3d(0, 0, 0);à l'élément de problème a fonctionné pour moi. Dans mon cas, j'utilisais ScrollMagic
fidev
Rien de tout cela n'a fonctionné pour moi non plus. Dès que je fais défiler jusqu'à un certain point, les éléments qui ne sont plus visibles au-dessus de la fenêtre sont fusionnés, ainsi que certains éléments de la fenêtre. Je remarque une très légère mais indéniable "secousse" pendant le défilement après quoi les éléments sont arrosés. (C'est-à-dire: lisse - instable - comportement lisse, comme si un hoquet pendant le défilement.) C'est sur iPad.
cbmtrx
BTW Je viens de découvrir que sur un iPad Air 2, lorsqu'un élément spécifique à l'écran (une barre de navigation, dans ce cas) disparaît de l'écran, l'appareil «recharge» ce bloc - en utilisant uniquement la version grande, pas la version moyenne d'origine que la page chargée. What the ...
cbmtrx
Au cas où quelqu'un éprouverait la même bizarrerie que moi - légèrement différente de ce qui est décrit sur cette page - j'ai trouvé que l'utilisation $(window).width()au lieu de window.innerWidthjQuery faisait toute la différence pour iOS. Qui sait.
cbmtrx
13

Cibler tous les éléments sauf html: a *:not(html) causé des problèmes sur d'autres éléments dans mon cas. Il a modifié le contexte d'empilement, provoquant la rupture de certains z-index.

Nous devrions mieux essayer de cibler le bon élément et de l'appliquer -webkit-transform: translate3d(0,0,0)uniquement.

Edit: parfois translate3D(0,0,0)cela ne fonctionne pas, nous pouvons utiliser la méthode suivante, en ciblant le bon élément:

@keyframes redraw{
    0% {opacity: 1;}
    100% {opacity: .99;}
}

// ios redraw fix
animation: redraw 1s linear infinite;
Guillaume Gautier
la source
J'étais confronté au même problème. Vous pouvez utiliser le body *sélecteur au lieu de *:not(html). Cela résoudra votre problème.
kunal
Félicitations pour la suggestion de cibler les bons éléments plutôt que de tout polluer avec le *
Maciek Rek
7

Lorsque translate3d ne fonctionne pas, essayez d'ajouter de la perspective. Ça marche toujours pour moi

transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
perspective: 1000;
-webkit-perspective: 1000;

http://blog.teamtreehouse.com/increase-your-sites-performance-with-hardware-accelerated-css

Fellipe Lima
la source
saint c $ # @ enfin une solution pour angulaire / ionique. -webkit-perspective: 1000;
lilbiscuit
Ahh a sauvé ma journée. +1 pour vous;)
Omar Bahir
Cela a fait planter mon navigateur iOS.
Andreas Richter
-webkit-perspective: 1000;je l'ai fait pour moi - merci
jHilscher
2

L'ajout -webkit-transform: translate3d(0,0,0)statique à un élément ne fonctionne pas pour moi.

J'applique cette propriété de manière dynamique. Par exemple, lorsqu'une page défile, je mets -webkit-transform: translate3d(0,0,0)sur un élément. Ensuite, après un court délai, je réinitialise cette propriété, c'est-à-dire que -webkit-transform: none cette approche semble fonctionner.

Merci, @Colin Williams de m'avoir pointé dans la bonne direction.

Alexander Poleschuk
la source
Cette astuce m'a beaucoup aidé, puisque ces styles ont des effets secondaires indésirables, je veux généralement éviter. J'utilise donc des événements touchstart / touchend pour les ajouter et les supprimer. Merci!
Windwalker
1

J'ai eu le même problème avec iscroll 4.2.5 sur ios7. L'élément de défilement entier disparaît simplement. J'ai essayé d'ajouter translate3d(0,0,0)comme cela a été suggéré ici, cela a résolu le problème, mais cela a désactivé l'effet "snap" iscroll. La solution est venue de donner des "position:relative; z-index:1000;display:block"propriétés css à l'ensemble du conteneur qui contient l'élément scroll et il n'est pas nécessaire de donner translate3d aux éléments enfants.

yudarik
la source
J'ai utilisé cette technique pour résoudre un problème similaire sur Android Chrome. Le défilement vertical semblait mieux fonctionner que lorsque j'ai essayé le correctif translate3d. Dans mon cas, l' <body>élément est ce que j'ai utilisé pour le défilement et une version simplifiée a fonctionné:body { position: relative; z-index: 0; }
BumbleB2na
1

À la fois translate3dpeut ne pas fonctionner, dans ces cas perspectivepeut être utilisé

transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
perspective: 1000;
-webkit-perspective: 1000;
Nidhin Joseph
la source
0

Je suis sûr que je viens de résoudre ce problème avec:

overflow-y: auto;

(Vraisemblablement, overflow: auto;cela fonctionnerait aussi en fonction de vos besoins.)

David Notik
la source
Cela n'a rien fait pour moi alors que la réponse acceptée le faisait probablement dans un scénario différent
Tony
0

Il existe des cas où une rotation est appliquée et / ou un index Z est utilisé.

Rotation : une déclaration existante de -webkit-transformfaire pivoter un élément peut ne pas être suffisante pour résoudre également le problème d'apparence (comme -webkit-transform: rotate(-45deg)). Dans ce cas, vous pouvez utiliser -webkit-transform: translateZ(0px) rotateZ(-45deg)comme astuce ( attention à la rotation Z ).

Index Z : avec la rotation, vous pouvez définir une z-indexpropriété positive , comme z-index: 42. Les étapes ci-dessus décrites sous "Rotation" étaient dans mon cas suffisantes pour résoudre le problème, même avec le vide translateZ(0px). Je soupçonne cependant que l'indice Z dans ce cas peut avoir causé la disparition et la réapparition en premier lieu. Dans tous les cas, la z-index: 42propriété doit être conservée - cela -webkit-transform: translateZ(42px)ne suffit pas.

Stefan Zurfluh
la source
0

C'est un problème très courant auquel sont confrontés les développeurs et qui est principalement dû à la Safari'spropriété de ne pas recréer les éléments définis comme position : fixed.

Donc, changez la propriété de position ou un piratage doit être appliqué comme mentionné dans d'autres réponses.

Lien1

Lien2

Arqam
la source
0

Dans mon cas (une application iOS Phonegap), l'application de translate3d à des éléments enfants relatifs n'a pas résolu le problème. Mon élément défilable n'avait pas de hauteur définie car il était absolument positionné et je définissais les positions supérieure et inférieure. Ce qui l'a corrigé pour moi a été d'ajouter une hauteur min (de 100 pixels).

b4tch
la source
0

J'ai eu le même problème avec une ancienne version de Fancybox. La mise à niveau vers la v3 résoudra votre problème OU vous pouvez simplement ajouter:

html, body {
    -webkit-overflow-scrolling : touch !important;
    overflow: auto !important;
    height: 100% !important;
}
Adam Touhou
la source
0

J'ai rencontré ce problème dans un projet Framework7 & Cordova. J'ai essayé toutes les solutions ci-dessus. Ils n'ont pas résolu mon problème.

Dans mon cas, j'utilisais plus de 10 animations css sur la même page avec une rotation infinie (transformation). J'ai dû supprimer les animations. Cela va maintenant avec le manque de certaines fonctionnalités visuelles.

Si les solutions ci-dessus ne vous aident pas, vous pouvez commencer à éliminer certaines animations.

yavuzkirez
la source
0

l' -webkit-transform: translate3d(0, 0, 0);astuce n'a pas fonctionné pour moi. Dans mon cas, j'avais demandé à un parent:

// parent
height: 100vh;

Changer cela en:

height: auto;
min-height: 100vh;

Résolution du problème au cas où quelqu'un d'autre serait confronté à la même situation.

funador
la source
0

Dans mon cas, CSS n'a pas résolu le problème. J'ai remarqué le problème lors de l'utilisation de jQuery re-rendre un bouton.

$("#myButton").html("text")

Essaye ça

$("#myButton").html("<span>text</span>")
Josh Stovall
la source