web-dev-qa-db-fra.com

iPhone Web App - Arrêtez le défilement du corps

Je suis en train de créer une application Web pour iPhone et, depuis iOS5, vous pouvez maintenant utiliser position: fixed; pour en-têtes etc. etc.

Bien que cela fonctionne, si vous faites défiler vers le haut en haut d'une page, il affiche la zone grise habituelle pendant un certain temps avant que vous ne puissiez plus faire défiler 

Example

Est-il possible d'arrêter ce défilement? J'ai essayé des choses comme débordement: caché; mais je n'arrive pas à trouver quoi que ce soit.

P.S. Je veux seulement que la seule chose pour arrêter de faire défiler, j'ai un div nommé #container que je veux toujours avoir la possibilité de faire défiler.

24
Oyed

Après avoir passé en revue plusieurs solutions, j'ai commencé à créer une solution personnalisée:

bouncefix.js

http://jaridmargolin.github.io/bouncefix.js/

Usage:

bouncefix.add (el)

Appliquez fix pour que l'élément donné ne provoque plus de rebond élastique sur tout le corps lors du défilement à l'extrême.

bouncefix.remove (el)

Supprimez tous les écouteurs/observateurs responsables de la fixation du rebond élastique du corps entier.

Pourquoi?

Scrollfix était un bon début, mais j’ai remarqué plusieurs problèmes:

  1. Cela fonctionnait seulement quand il y avait un contenu défilable Si vous aviez une page vide .__, l'effet de rebond sur le corps se produirait.
  2. L'API n'a pas exposé de méthode pour supprimer les écouteurs. Mon application aura Plusieurs pages, et il n’était pas judicieux de garder tous les auditeurs Attachés lorsque l’utilisateur se déplaçait dans l’application.

Comment?

Il utilise une approche similaire à celle de scrollfix. Le problème se produit lorsque vous vous trouvez à l'un des extrêmes de défilement. Sur touchstart, nous regardons si nous sommes au sommet ou au sommet, en ajoutant 1px si nous sommes au sommet et en supprimant 1px si nous sommes au bas.

Malheureusement, cette astuce ne fonctionne que si nous sommes en mesure de définir la valeur scrollTop. Par exemple, si vous ne pouvez pas faire défiler le contenu, par exemple, vous n’avez qu’un élément de liste, le corps entier défilera à nouveau. Bouncefix.js s’occupera de tout cela en coulisse en utilisant la délégation d’événements et en comparant scrollHeight et offsetHeight chaque fois qu’un touchstart est déclenché. S'il n'y a pas de contenu défilable, tout le défilement sur le conteneur est bloqué avec e.preventDefault ();

16
Jarid R. Margolin

ce qui a fonctionné pour moi:

html, body, .scrollable {
    overflow: auto; 
    -webkit-overflow-scrolling: touch;
}

plus (en utilisant jQuery ...)

$(function() {
  $(document).on("touchmove", function(evt) { evt.preventDefault() });
  $(document).on("touchmove", ".scrollable", function(evt) { evt.stopPropagation() });
});

il est important que l'appel evt.stopPropagation() utilise un délégué, étant donné qu'il est également saisi dans le document mais annulé à la dernière seconde. 

En effet, cela intercepte tous les événements touchmove du document, mais si l'événement d'origine a été généré par un .scrollable, nous avons simplement stopPropagation au lieu d'annuler l'événement.

11
Jiaaro

Essayez de placer ceci en haut de votre fichier JS.

document.ontouchmove = function(event){
    event.preventDefault();
}

Cela vous empêchera de faire défiler votre page, vous ne pourrez donc pas voir la "zone grise" en haut.

Source: Empêcher UIWebView de "rebondir" verticalement?

10
Ben Clayton

Mettre à jour:

Cette question a été pénible pour beaucoup de gens, mais voici une solution solide créée par bjrn :

Démo:http://rixman.net/demo/scroll/
Et il y a une discussion à ce sujet ici: https://github.com/joelambert/ScrollFix/issues/2

Ceci a été posté par ryan en réponse à une question de moi: Empêcher le toucher par défaut sur le parent mais pas sur l'enfant .

J'espère que cela aide certaines personnes.


Réponse originale:

En fait, je suis en train d'examiner le même problème et je suis tombé sur ceci:

https://github.com/joelambert/ScrollFix

Je l'ai essayé et cela fonctionne presque parfaitement. Si vous copiez tout le code dans une démonstration et que vous le lancez sur iOS, vous ne verrez pas l’arrière-plan gris, sauf si vous attrapez la barre noire et essayez de le faire défiler. Cependant, il devrait être assez facile d’utiliser le code fourni par Ben pour éviter que cela ne se produise (preventDefault ()).

J'espère que ça aide (ça m'a certainement aidé!)

5
will

Comme d'autres l'ont suggéré, j'ai écrit une fonction rapide qui repousse mon pixel défilant à chaque défilement vers le haut ou le bas pour empêcher toute la page de glisser. C'est bien pour mon div à défilement, mais les div fixes sur ma page étaient toujours susceptibles de glisser de page. J'ai accidentellement remarqué que lorsque je superposais un div fixe au-dessus de mon div à défilement (qui ne traînait plus la page à cause de ma fonction bump), les événements de glisser-déplacer étaient passés par le div fixe au div à défilement situé au-dessous, ce qui n'était pas plus un dragueur de page potentiel. Sur cette base, j’ai pensé qu’il serait peut-être possible d’utiliser une div à défilement plein écran à l’arrière-plan comme base de la page entière pour que tous les déplacements soient passés et que les éléments réels situés en haut soient sécurisés. La div de fondation a besoin de faire défiler, alors j'ai placé une div de remplissage à l'intérieur de celle-ci et je l'ai légèrement agrandie pour garantir son défilement. Et ça a marché! Vous trouverez ci-dessous un exemple utilisant cette idée pour empêcher le glissement de page. Désolé si cela est évident ou déjà posté mais je ne l'ai pas vu ailleurs et cela a vraiment amélioré mon application web. S'il vous plaît essayez-le et laissez-moi savoir si cela aide.

<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">

<style>
.myDiv {
    position:absolute;
    left:0;
    width:100%;
    color:white;
}

.myDiv.hidden {
    top:0;
    height:100%;
    -webkit-overflow-scrolling:touch;
    overflow-y:scroll;
}

.myDiv.title {
    top:0;
    height:30%;
    background-color:#6297BC;
}

.myDiv.scroll {
    bottom:0;
    height:70%;
    -webkit-overflow-scrolling:touch;
    overflow-y:scroll;
    background-color:#ADADAD;
}
</style>

<script>
function setup() {  
    hiddenScrollingDiv.addEventListener("scroll", preventWindowScroll);
    visibleScrollingDiv.addEventListener("scroll", preventWindowScroll);
    hiddenScrollingDiv.style.height=window.innerHeight; 
    visibleScrollingDiv.style.height=parseInt(window.innerHeight*.7)+1; 
    fillerDiv.style.height=window.innerHeight+2;
    hiddenScrollingDiv.scrollTop=1;
    visibleScrollingDiv.scrollTop=1;
}

function preventWindowScroll(evt) {
    if (evt.target.scrollTop==0) evt.target.scrollTop=1;
    else if (evt.target.scrollTop==(evt.target.scrollHeight-parseInt(evt.target.style.height))) evt.target.scrollTop=evt.target.scrollHeight-parseInt(evt.target.style.height)-1;
}
</script>
</head>

<body onload="setup()">
<div id="hiddenScrollingDiv" class="myDiv hidden"><div id="fillerDiv"></div></div>
<div id="visibleTitleDiv" class="myDiv title"><br><center>Non-scrolling Div</center></div>

<div id="visibleScrollingDiv" class="myDiv scroll">
<ul>
    <li style="height:50%">Scrolling Div</li>
    <li style="height:50%">Scrolling Div</li>
    <li style="height:50%">Scrolling Div</li>
</ul>
</div>

</body>
</html>
1
Shawn

Une solution précédente suggérée:

document.ontouchmove = function(event){
    event.preventDefault();
}

Cependant, cela empêche également le défilement de l'élément d'intérêt.

Afin de surmonter cela, on peut faire ce qui suit:

  1. Détecter quand le haut/bas d’un élément d’intérêt (modal, par exemple) est passé à.
  2. Si vous faites défiler l'écran vers le bas, utilisez la technique preventDefault ci-dessus pour l'événement ontouchmove, mais UNIQUEMENT SI, l'utilisateur tente de faire défiler l'écran davantage.
  3. Si l'utilisateur tente de faire défiler vers le haut, ne plus preventDefault.
  4. Vice versa s’applique si top est sélectionné.

Voici le code source pour une implémentation de la logique ci-dessus.

Le package npm peut également être téléchargé pour plus de commodité (testé avec Vanilla JS/React sur un safari mobile/desktop iOS ainsi que sur Android/Desktop Chrome).

Checkout https://medium.com/jsdownunder/locking-body-scroll-for-all-devices-22def9615177 pour plus d'explications sur les différentes approches.

0
Will Po