ipad safari: wyłączyć przewijanie i efekt odbijania?


126

Pracuję nad aplikacją opartą na przeglądarce, obecnie rozwijam i projektuję dla przeglądarki iPad Safari.

Szukam dwóch rzeczy na iPadzie: Jak wyłączyć przewijanie w pionie na stronach, które tego nie wymagają? i jak mogę wyłączyć efekt sprężystego odskoku?


odnieś się do następującej odpowiedzi, tylko taka, która działała dla mnie i jest aktualna ( stackoverflow.com/a/51176339/1979180 )
frage

Odpowiedzi:


157

Ta odpowiedź nie ma już zastosowania, chyba że tworzysz oprogramowanie dla bardzo starego urządzenia z systemem iOS ... Zobacz inne rozwiązania


Odpowiedź z 2011 roku: W przypadku aplikacji internetowej / html działającej w iOS Safari potrzebujesz czegoś podobnego

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

W przypadku iOS 5 warto wziąć pod uwagę: document.ontouchmove i przewijanie w iOS 5

Aktualizacja wrzesień 2014: Dokładniejsze podejście można znaleźć tutaj: https://github.com/luster-io/prevent-overscroll . Informacje na ten temat oraz wiele przydatnych porad dotyczących aplikacji internetowych można znaleźć pod adresem http://www.luster.io/blog/9-29-14-mobile-web-checklist.html

Aktualizacja z marca 2016 r .: Ten ostatni link nie jest już aktywny - zobacz https://web.archive.org/web/20151103001838/http://www.luster.io/blog/9-29-14-mobile-web-checklist .html dla wersji zarchiwizowanej. Dzięki @falsarella za wskazanie tego.


1
Mam aplikację internetową działającą w iOS Safari i próbowałem wyłączyć zdarzenie ontouchmove, ale nadal można zobaczyć efekt odbicia, jeśli zostanie to zrobione ostrożnie. (iOS 5)
Nilesh

7
A co z wyłączeniem efektu odbijania ...?
Yuval A.

6
Problem z tym podejściem polega na tym, że przewijalne elementy div w Twoim domenie nie będą już przewijać. W zależności od konfiguracji domeny można to obejść.
huesforalice

3
Jest tu grupa ludzi, którzy pytają o przewijanie elementów div podczas korzystania z tego, więc ... aby umożliwić przewijanie tych elementów div, dodaj. onTouchMove: function(e) { e.stopPropagation(); e.stopImmediatePropagation(); } Zapobiegnie to uderzaniu zdarzenia w ciało, ale treść nie będzie odbijana. Edycja: Zakładamy, że ustawiłeś $ ('div'). On ('touchmove', ... onTouchMove);
Matt Kenefick

1
@OskarAustegard Ostatni link nie działał dla mnie, ale mogłem znaleźć zawartość w archiwum internetowym: web.archive.org/web/20151103001838/http://www.luster.io/blog/…
falsarella

116

Możesz także zmienić położenie body / html na naprawione:

body,
html {
  position: fixed;
}

2
To faktycznie działało bardzo dobrze na iPadzie iOS 8.2 Safari; brak efektu odbijania.
Akseli Palén

3
Najlepszy sposób na zrobienie tego, jaki widziałem do tej pory
hildende

8
Nie działa, jeśli chcesz umieścić coś z pozycją: bezwzględną i wszystkimi bokami ustawionymi na 0 (aby utworzyć pełnoekranowy element div) - cały dokument kurczy się do zera.
riv

4
Strona przeskakuje z powrotem na górę strony, kiedy jej używam, a następnie skupiam się na danych wejściowych. Czy znasz sposób na obejście tego?
Julie

1
@riv dodając szerokość: 100%; wysokość: 100% zarówno body, jak i html pomogły mi.
Tim

58

Aby zapobiec przewijaniu w nowoczesnych przeglądarkach mobilnych, musisz dodać pasywne: false. Wyrywałem sobie włosy, żeby to zadziałało, dopóki nie znalazłem tego rozwiązania. Znalazłem to wspomniane tylko w jednym miejscu w Internecie.

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

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


7
Bez { passive: false }tego na pewno nie działa !!! Witaj na StackOverflow dude
Ser

2
Dziękuję za to rozwiązanie!
Paul Z.

6
To jest poprawna odpowiedź. Możesz zobaczyć wyjaśnienie tutaj: developer.mozilla.org/en-US/docs/Web/API/EventTarget/ ... po tym, jak touchmove Chrome 54 domyślnie ustawił wartość pasywną na true, co oznacza, że ​​wywołania disableDefault byłyby ignorowane. Dlatego musisz przekazać {passive: false}, aby wywołanie prevDefault nie było ignorowane.
derickito

1
Deklarujesz funkcję w JS - Ale jak wywołać tę funkcję na elemencie, aby działała zgodnie z sugestią?
ikwyl6

4
Działa to świetnie, jeśli chcesz wyłączyć wszystkie rodzaje przewijania. Ale co, jeśli chcę tylko wyłączyć przewijanie treści i zachować możliwość przewijania elementu overflow-y: scroll? Na przykład mając modal z wyższą wysokością widoku niż ciało.
Calsal

7

Możesz użyć tego fragmentu kodu jQuery, aby to zrobić:

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

Spowoduje to zablokowanie przewijania w pionie, a także wszelkich efektów odbijania się na Twoich stronach.


11
To nie jest JavaScript, to jQuery. Powinieneś o tym wspomnieć, nie wszyscy używają tego frameworka.
inta

jak zatrzymać odbijanie lub przewijanie w poziomie
fidel castro

Przewijanie poziome można nawet wyłączyć za pomocą samego css, stosując overflow-x: hidden; do głównego pojemnika. Zauważyłem, że w najnowszych wersjach Safari nie można jednak wyłączyć efektu odbicia. To natywna funkcja przeglądarki na urządzeniach mobilnych.
Alessandro Incarnati

6
@inta Mówiąc, że to w rzeczywistości jest JavaScript. To po prostu nie jest czysty javascript.
Ben Lorantfy


4

Wiem, że jest to trochę poza trasą, ale używałem Swiffy do konwersji Flasha na interaktywną grę HTML5 i napotkałem ten sam problem z przewijaniem, ale nie znalazłem rozwiązania, które działało.

Problem, jaki miałem, polegał na tym, że scena Swiffy zajmowała cały ekran, więc po załadowaniu zdarzenie dotknięcia dokumentu nigdy nie zostało wyzwolone.

Jeśli próbowałem dodać to samo zdarzenie do kontenera Swiffy, zostało ono zastąpione zaraz po załadowaniu sceny.

W końcu rozwiązałem to (raczej niechlujnie), stosując zdarzenie touchmove do każdego DIV na scenie. Ponieważ te elementy div również się zmieniały, musiałem je sprawdzać.

To było moje rozwiązanie, które wydaje się działać dobrze. Mam nadzieję, że będzie to pomocne dla każdego, kto próbuje znaleźć to samo rozwiązanie co ja.

var divInterval = setInterval(updateDivs,50);
function updateDivs(){
$("#swiffycontainer > div").bind(
    'touchmove',
     function(e) {
        e.preventDefault();
    }
);}

to wyłącza całe przewijanie w iPadzie
fidel castro

3

Kod do usuwania ipad safari: wyłącz przewijanie i efekt odbijania

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

Jeśli masz tag canvas w dokumencie, czasami będzie to miało wpływ na użyteczność obiektu wewnątrz Canvas (przykład: ruch obiektu); więc dodaj poniższy kod, aby to naprawić.

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

2

Spróbuj tego rozwiązania 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();
    }
});

Zapobiega domyślnemu przewijaniu i odbijaniu gestów przeglądarki Safari bez odłączania detektorów zdarzeń dotykowych.


Dzięki temu aplikacja internetowa nie będzie całkowicie przewijała elementu body.
MartijnICU

2

żadne z rozwiązań nie działa dla mnie. Tak to robię.

  html,body {
      position: fixed;
      overflow: hidden;
    }
  .the_element_that_you_want_to_have_scrolling{
      -webkit-overflow-scrolling: touch;
  }

Zrobiłbym .the_element_that_you_want_to_have_scrolling {scrolling: touch; }
Roy Segall,

Twoja odpowiedź zadziałała dla mnie w przypadku treści HTML, ale nie mogę przewinąć „the_element_that_you_want_to_have_scrolling”. Ten element jest zagnieżdżony w kilku elementach div znajdujących się pod treścią. Czy ma znaczenie, jakie byłyby typowe znaczniki elementu dla tego zagnieżdżonego elementu div, że chcę, aby był przewijany? Mam pozycję: względną.
ikwyl6


1

Dla tych, którzy używają MyScript aplikacji internetowej i zmagają się z przewijaniem / przeciąganiem ciała (na iPadzie i tabletach) zamiast pisać:

<body touch-action="none" unresolved>

To naprawiło to dla mnie.


1

Możesz użyć js, aby zapobiec przewijaniu:

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

I niż tylko uruchamianie / zatrzymywanie toggleScrollfunkcji podczas otwierania / zamykania trybu.

Lubię to toggleScroll(true) / toggleScroll(false)

(To jest tylko dla iOS, na Androidzie nie działa)


1

Wypróbuj to rozwiązanie JS, które przełącza webkitOverflowScrollingstyl. Sztuczka polega na tym, że ten styl jest wyłączony, mobilne Safari przechodzi do zwykłego przewijania i zapobiega nadmiernemu odbiciu - niestety nie jest w stanie anulować trwającego przeciągania. To złożone rozwiązanie śledzi również, onscrollgdy odbicie od góry sprawia, scrollTopże wartość ujemna może być śledzona. To rozwiązanie zostało przetestowane na iOS 12.1.1 i ma jedną wadę: podczas przyspieszania przewijania nadal występuje pojedyncze przeskakiwanie, ponieważ resetowanie stylu może nie anulować go natychmiast.

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

1

poprawiona odpowiedź @Ben Bos i skomentowana przez @Tim

Ten CSS pomoże uniknąć problemów z przewijaniem i wydajnością przy ponownym renderowaniu CSS, ponieważ pozycja została zmieniona / niewielkie opóźnienie bez szerokości i wysokości

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


Na IOS13 jest to dla mnie najczystsze rozwiązanie i nie znalazłem jeszcze żadnych wad ...
Soylent Graham

0

Dla tych z Was, którzy nie chcą pozbyć się odbijania, ale chcą tylko wiedzieć, kiedy się zatrzymają (na przykład, aby rozpocząć obliczenia odległości ekranu), mogą wykonać następujące czynności (kontener to przepełniony element kontenera):

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

0

Wyłącz efekt przewijania odbijania safari:

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

-1

Podobnie jak w przypadku złego kiwi, sprawiłem, że działa na podstawie wysokości, a nie pozycji:

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

.the_element_that_you_want_to_have_scrolling{
  -webkit-overflow-scrolling: touch;
}

jako dokument umożliwi to odbicie również po nie wyłączeniu pędu
CaSUaL

@CaSUaL Nie wiesz, co masz na myśli? To rozwiązanie zadziałało w moim przypadku użycia ...
austinh7

-1

Rozwiązanie przetestowane, działa na iOS 12.x.

Oto problem, który napotkałem:

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

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

  </article>
</body>

Kiedy przewijam galerię, ciało zawsze przewija się (ruchy człowieka nie są tak naprawdę poziome), przez co moja galeria jest bezużyteczna.

Oto, co zrobiłem, gdy moja galeria zaczęła się przewijać

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

A kiedy moja galeria zakończy przewijanie ...

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

Mam nadzieję, że to pomoże ~

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.