ipad safari: désactiver le défilement et l'effet de rebond?

126

Je travaille sur une application basée sur un navigateur, actuellement je développe et stylise pour le navigateur iPad Safari.

Je recherche deux choses sur l'ipad: Comment puis-je désactiver le défilement vertical pour les pages qui n'en ont pas besoin? & comment puis-je désactiver l'effet de rebond élastique?

Adam
la source
se référer à la réponse suivante seulement celle qui a fonctionné pour moi et qui est actuelle ( stackoverflow.com/a/51176339/1979180 )
frage

Réponses:

157

Cette réponse n'est plus applicable, sauf si vous développez pour un très ancien appareil iOS ... Veuillez voir d'autres solutions


Réponse de 2011: pour une application web / html exécutée dans iOS Safari, vous voulez quelque chose comme

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

Pour iOS 5, vous voudrez peut-être prendre en compte les éléments suivants: document.ontouchmove et défilement sur iOS 5

Mise à jour de septembre 2014: Une approche plus approfondie peut être trouvée ici: https://github.com/luster-io/prevent-overscroll . Pour cela et de nombreux conseils utiles sur les applications Web, consultez http://www.luster.io/blog/9-29-14-mobile-web-checklist.html

Mise à jour de mars 2016: ce dernier lien n'est plus actif - voir https://web.archive.org/web/20151103001838/http://www.luster.io/blog/9-29-14-mobile-web-checklist .html pour la version archivée à la place. Merci @falsarella pour l'avoir signalé.

Oskar Austegard
la source
1
J'ai une application web exécutée dans iOS Safari et j'ai essayé de désactiver l'événement ontouchmove, mais il est toujours possible de voir l'effet de rebond si cela est fait avec soin. (iOS 5)
Nilesh
7
Qu'en est-il simplement de désactiver l'effet de rebond ...?
Yuval A.
6
Le problème avec cette approche est que les divs défilables dans votre dom ne défileront plus. En fonction de votre configuration dom, il existe des moyens de contourner ce problème.
huesforalice
3
Il y a un tas de gens ici qui demandent comment faire défiler les divs tout en utilisant ceci donc .. pour rendre ces divs scrollables, ajoutez onTouchMove: function(e) { e.stopPropagation(); e.stopImmediatePropagation(); } Cela empêchera l'événement de toucher le corps, mais le corps restera non rebondissant. Edit: Cela suppose que vous définissez $ ('div'). On ('touchmove', ... onTouchMove);
Matt Kenefick
1
@OskarAustegard Le dernier lien n'a pas fonctionné pour moi, mais j'ai pu trouver le contenu sur l'archive Web: web.archive.org/web/20151103001838/http://www.luster.io/blog/…
falsarella
116

Vous pouvez également modifier la position du corps / html en fixe:

body,
html {
  position: fixed;
}
Ben Bos
la source
2
Cela fonctionnait très bien sur iPad iOS 8.2 Safari; plus d'effet de rebond.
Akseli Palén
3
Meilleur moyen de faire cela que j'ai vu jusqu'à présent
hildende
8
Ne fonctionne pas si vous voulez placer quelque chose avec la position: absolue et tous les côtés mis à 0 (pour faire un div plein écran) - tout votre document se réduit à rien.
riv
4
La page revient en haut de la page pour moi lorsque j'utilise ceci, puis je me concentre sur une entrée. Connaissez-vous un moyen de contourner cela?
Julie
1
@riv ajout de largeur: 100%; hauteur: 100% pour le corps et le html m'a aidé.
Tim
58

Pour éviter le défilement sur les navigateurs mobiles modernes, vous devez ajouter le passif: false. J'avais arraché mes cheveux pour que cela fonctionne jusqu'à ce que je trouve cette solution. Je n'ai trouvé cela mentionné qu'à un autre endroit sur Internet.

function preventDefault(e){
    e.preventDefault();
}

function disableScroll(){
    document.body.addEventListener('touchmove', preventDefault, { passive: false });
}
function enableScroll(){
    document.body.removeEventListener('touchmove', preventDefault);
}

Christopher Vickers
la source
7
Sans { passive: false }ça ne marche certainement pas !!! Bienvenue sur StackOverflow mec
Ser
2
Je vous remercie d'avoir fourni cette solution!
Paul Z.29
6
C'est la bonne réponse. Vous pouvez voir l'explication ici: developer.mozilla.org/en-US/docs/Web/API/EventTarget/… après que Chrome 54 touchmove ait défini le passif par défaut sur true, ce qui signifie que les appels de preventDefault seraient ignorés. C'est pourquoi vous devez passer {passive: false} pour que l'appel preventDefault ne soit pas ignoré.
derickito
1
Vous déclarez la fonction dans JS - Mais comment appeler cette fonction sur un élément pour qu'elle fonctionne comme suggéré?
ikwyl6
4
Cela fonctionne très bien si vous souhaitez désactiver toutes sortes de défilement. Mais que faire si je veux seulement désactiver le défilement sur le corps et garder la possibilité de faire défiler un élément avec overflow-y: scroll? Par exemple, avoir un modal avec une hauteur de vue plus haute que le corps.
Calsal
7

Vous pouvez utiliser cet extrait de code jQuery pour ce faire:

$(document).bind(
      'touchmove',
          function(e) {
            e.preventDefault();
          }
);

Cela bloquera le défilement vertical et tout effet de rebond se produisant sur vos pages.

Alessandro Incarnati
la source
11
Ce n'est pas Javascript, c'est jQuery. Vous devriez mentionner que tout le monde n'utilise pas ce cadre.
entre le
comment puis-je arrêter le rebond horizontal ou le défilement
fidel castro
Défilement horizontal, vous pouvez même le désactiver avec juste css, en appliquant overflow-x: hidden; dans votre conteneur principal. J'ai remarqué que dans les dernières versions de safari, vous ne pouvez pas désactiver l'effet de rebond. C'est une fonctionnalité native du navigateur sur les appareils mobiles.
Alessandro Incarnati
6
@inta Simplement dire ceci est en fait du javascript. Ce n'est tout simplement pas du javascript pur.
Ben Lorantfy
6
overflow: scroll;
-webkit-overflow-scrolling: touch;

Sur le conteneur, vous pouvez définir un effet de rebond à l'intérieur de l'élément

Source: http://www.kylejlarson.com/blog/2011/fixed-elements-and-scrolling-divs-in-ios-5/

user956584
la source
1
Avec overflow:hiddensur le <body>, c'est toujours la meilleure solution. Cependant, lors de l'ouverture du clavier ou du glissement sur le bas de l'écran, cela ne fonctionnera plus.
Fabian von Ellerts
essayer l'entrée onfocus supprimer le débordement
user956584
4

Je sais que c'est un peu hors piste, mais j'utilise Swiffy pour convertir Flash en un jeu HTML5 interactif et j'ai rencontré le même problème de défilement, mais je n'ai trouvé aucune solution qui fonctionnait.

Le problème que j'avais était que la scène Swiffy occupait tout l'écran, donc dès qu'il était chargé, l'événement touchmove du document n'était jamais déclenché.

Si j'essayais d'ajouter le même événement au conteneur Swiffy, il était remplacé dès que la scène était chargée.

En fin de compte, je l'ai résolu (plutôt désordonné) en appliquant l'événement touchmove à chaque DIV de la scène. Comme ces divs étaient également en constante évolution, je devais continuer à les vérifier.

C'était ma solution, qui semble bien fonctionner. J'espère que cela sera utile pour quiconque essaie de trouver la même solution que moi.

var divInterval = setInterval(updateDivs,50);
function updateDivs(){
$("#swiffycontainer > div").bind(
    'touchmove',
     function(e) {
        e.preventDefault();
    }
);}
À M
la source
cela désactive tout le défilement dans l'ipad
fidel castro
3

Code pour supprimer ipad safari: désactiver le défilement et l'effet de rebond

   document.addEventListener("touchmove", function (e) {
        e.preventDefault();
    }, { passive: false });

Si vous avez une balise canvas à l'intérieur du document, cela affectera parfois la convivialité de l'objet dans Canvas (exemple: mouvement de l'objet); alors ajoutez le code ci-dessous pour le réparer.

    document.getElementById("canvasId").addEventListener("touchmove", function (e) {
        e.stopPropagation();
    }, { passive: false });
Teju VB
la source
2

Essayez ce sollutuion JS :

var xStart, yStart = 0; 

document.addEventListener('touchstart', function(e) {
    xStart = e.touches[0].screenX;
    yStart = e.touches[0].screenY;
}); 

document.addEventListener('touchmove', function(e) {
    var xMovement = Math.abs(e.touches[0].screenX - xStart);
    var yMovement = Math.abs(e.touches[0].screenY - yStart);
    if((yMovement * 3) > xMovement) {
        e.preventDefault();
    }
});

Empêche le défilement par défaut de Safari et les mouvements de rebond sans détacher vos écouteurs d'événements tactiles.

Andrii Verbytskyi
la source
Cela empêche l'application Web de défiler complètement sur l'élément de corps.
MartijnICU
2

aucune des solutions ne fonctionne pour moi. Voilà comment je fais.

  html,body {
      position: fixed;
      overflow: hidden;
    }
  .the_element_that_you_want_to_have_scrolling{
      -webkit-overflow-scrolling: touch;
  }
kiwi en colère
la source
Je ferais .the_element_that_you_want_to_have_scrolling {scrolling: touch; }
Roy Segall
Votre réponse a fonctionné pour moi pour le corps html, mais je ne peux pas faire défiler "the_element_that_you_want_to_have_scrolling". Cet élément est imbriqué dans quelques divs sous le corps. Est-ce que les balises d'élément typiques seraient importantes pour ce div imbriqué que je veux faire défiler? J'ai la position: relative.
ikwyl6
1

Pour ceux qui utilisent MyScript l'application Web et ont du mal à faire défiler / glisser le corps (sur iPad et tablettes) au lieu d'écrire:

<body touch-action="none" unresolved>

Cela a réglé le problème pour moi.

Miro
la source
1

Vous pouvez utiliser js pour empêcher le défilement:

let body = document.body;

let hideScroll = function(e) {
  e.preventDefault();
};

function toggleScroll (bool) {

  if (bool === true) {
    body.addEventListener("touchmove", hideScroll);
  } else {
    body.removeEventListener("touchmove", hideScroll);
  }
}

Et que de simplement exécuter / arrêter toggleScrollfunc lorsque vous ouvrez / fermez modal.

Comme ça toggleScroll(true) / toggleScroll(false)

(Ceci est uniquement pour iOS, sur Android ne fonctionne pas)

Vlad Novikov
la source
1

Essayez cette solution JS qui change de webkitOverflowScrollingstyle. L'astuce ici est que ce style est désactivé, Safari mobile passe au défilement ordinaire et empêche le sur-rebond - hélas, il n'est pas capable d'annuler le glissement en cours. Cette solution complexe suit également onscrolllorsque le rebond sur le dessus rend le scrollTopnégatif qui peut être suivi. Cette solution a été testée sur iOS 12.1.1 et présente un seul inconvénient: lors de l'accélération du défilement, un sur-rebond unique se produit toujours, car la réinitialisation du style peut ne pas l'annuler immédiatement.

function preventScrollVerticalBounceEffect(container) {
  setTouchScroll(true) //!: enable before the first scroll attempt

  container.addEventListener("touchstart", onTouchStart)
  container.addEventListener("touchmove", onTouch, { passive: false })
  container.addEventListener("touchend", onTouchEnd)
  container.addEventListener("scroll", onScroll)

  function isTouchScroll() {
    return !!container.style.webkitOverflowScrolling
  }

  let prevScrollTop = 0, prevTouchY, opid = 0

  function setTouchScroll(on) {
    container.style.webkitOverflowScrolling = on ? "touch" : null

    //Hint: auto-enabling after a small pause makes the start
    // smoothly accelerated as required. After the pause the
    // scroll position is settled, and there is no delta to
    // make over-bounce by dragging the finger. But still,
    // accelerated content makes short single over-bounce
    // as acceleration may not be off instantly.

    const xopid = ++opid
    !on && setTimeout(() => (xopid === opid) && setTouchScroll(true), 250)

    if(!on && container.scrollTop < 16)
      container.scrollTop = 0
    prevScrollTop = container.scrollTop
  }

  function isBounceOverTop() {
    const dY = container.scrollTop - prevScrollTop
    return dY < 0 && container.scrollTop < 16
  }

  function isBounceOverBottom(touchY) {
    const dY = touchY - prevTouchY

    //Hint: trying to bounce over the bottom, the finger moves
    // up the screen, thus Y becomes smaller. We prevent this.

    return dY < 0 && container.scrollHeight - 16 <=
      container.scrollTop + container.offsetHeight
  }

  function onTouchStart(e) {
    prevTouchY = e.touches[0].pageY
  }

  function onTouch(e) {
    const touchY = e.touches[0].pageY

    if(isBounceOverBottom(touchY)) {
      if(isTouchScroll())
        setTouchScroll(false)
      e.preventDefault()
    }

    prevTouchY = touchY
  }

  function onTouchEnd() {
    prevTouchY = undefined
  }

  function onScroll() {
    if(isTouchScroll() && isBounceOverTop()) {
      setTouchScroll(false)
    }
  }
}
Anton Baukin
la source
1

réponse améliorée @Ben Bos et commentée par @Tim

Ce css aidera à éviter les problèmes de défilement et de performances avec le rendu css car la position a changé / peu de retard sans largeur et hauteur

body,
html {
  position: fixed;
  width: 100%; 
  height: 100%
}

auronsan zenx
la source
Sur IOS13, c'est la solution la plus propre pour moi, et pas encore trouvé d'inconvénients ...
Soylent Graham
0

Pour ceux d'entre vous qui ne veulent pas se débarrasser du rebond mais simplement savoir quand il s'arrête (par exemple pour commencer un calcul des distances d'écran), vous pouvez faire ce qui suit (le conteneur est l'élément conteneur qui déborde):

    const isBouncing = this.container.scrollTop < 0 ||
    this.container.scrollTop + this.container.offsetHeight >
        this.container.scrollHeight
Phil
la source
0

Désactiver l'effet de défilement de rebond safari:

html,
body {
  height: 100%;
  width: 100%;
  overflow: auto;
  position: fixed;
}  
Abolfazl Baghshahi
la source
-1

Similaire au kiwi en colère, je l'ai fait fonctionner en utilisant la hauteur plutôt que la position:

html,body {
  height: 100%;
  overflow: hidden;
}

.the_element_that_you_want_to_have_scrolling{
  -webkit-overflow-scrolling: touch;
}
Austinh7
la source
en tant que doc, cela
activera
@CaSUaL Vous ne savez pas ce que vous voulez dire? Cette solution a fonctionné pour mon cas d'utilisation ...
austinh7
-1

Solution testée, fonctionne sur iOS 12.x

C'est le problème que je rencontrais:

<body> <!-- the whole body can be scroll vertically -->
  <article>

    <my_gallery> <!-- some picture gallery, can be scroll horizontally -->
    </my_gallery>

  </article>
</body>

Pendant que je fais défiler ma galerie, le corps défile toujours lui-même (le balayage humain n'est pas vraiment horizontal), cela rend ma galerie inutile.

Voici ce que j'ai fait pendant que ma galerie commence à défiler

var html=jQuery('html');
html.css('overflow-y', 'hidden');
//above code works on mobile Chrome/Edge/Firefox
document.ontouchmove=function(e){e.preventDefault();} //Add this only for mobile Safari

Et quand ma galerie termine son défilement ...

var html=jQuery('html');
html.css('overflow-y', 'scroll');
document.ontouchmove=function(e){return true;}

J'espère que cela aide ~

RRTW
la source