iOS 10 Safari: Scrollen hinter einem festen Overlay verhindern und Scrollposition beibehalten

Lesezeit: 6 Minuten

Benutzer-Avatar
Gavin

Ich kann nicht verhindern, dass der Haupttextinhalt gescrollt wird, während ein Overlay mit fester Position angezeigt wird. Ähnliche Fragen wurden viele Male gestellt, aber alle Techniken, die zuvor funktionierten, scheinen auf Safari in iOS 10 nicht zu funktionieren. Dies scheint ein neues Problem zu sein.

Einige Notizen:

  • Ich kann das Scrollen deaktivieren, wenn ich beides einstelle html und body zu overflow: hiddenaber dadurch wird der Inhalt des Hauptteils nach oben gescrollt.
  • Wenn der Inhalt im Overlay lang genug ist, um gescrollt werden zu können, wird das Scrollen für den Inhalt der Hauptseite korrekt deaktiviert. Wenn der Inhalt im Overlay nicht lang genug ist, um ein Scrollen zu verursachen, können Sie den Inhalt der Hauptseite scrollen.
  • Ich habe eine Javascript-Funktion von eingefügt https://blog.christoffer.online/2015-06-10-six-things-i-learnt-about-ios-rubberband-overflow-scrolling/ das deaktiviert touchmove während das Overlay angezeigt wird. Das hat vorher funktioniert, funktioniert aber nicht mehr.

Hier ist die vollständige HTML-Quelle:

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <style type="text/css">
        html, body {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
        body {
            font-family: arial;
        }
        #overlay {
            display: none;
            position: fixed;
            z-index: 9999;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            overflow: scroll;
            color: #fff;
            background: rgba(0, 0, 0, 0.5);
        }
        #overlay span {
            position: absolute;
            display: block;
            right: 10px;
            top: 10px;
            font-weight: bold;
            font-size: 44px;
            cursor: pointer;
        }
        #overlay p {
            display: block;
            padding: 100px;
            font-size: 36px;
        }
        #page {
            width: 100%;
            height: 100%;
        }
        a {
            font-weight: bold;
            color: blue;
        }
    </style>
    <script>
        $(function() {
            $('a').click(function(e) {
                e.preventDefault();
                $('body').css('overflow', 'hidden');
                $('#page').addClass('disable-scrolling'); // for touchmove technique below

                $('#overlay').fadeIn();
            });
            $('#overlay span').click(function() {
                $('body').css('overflow', 'auto');
                $('#page').removeClass('disable-scrolling'); // for touchmove technique below

                $('#overlay').fadeOut();
            });
        });

        /* Technique from http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/ */
        document.ontouchmove = function ( event ) {
            var isTouchMoveAllowed = true, target = event.target;
            while ( target !== null ) {
                if ( target.classList && target.classList.contains( 'disable-scrolling' ) ) {
                    isTouchMoveAllowed = false;
                    break;
                }
                target = target.parentNode;
            }
            if ( !isTouchMoveAllowed ) {
                event.preventDefault();
            }
        };
    </script>
</head>

<body>
    <div id="overlay">
        <span>&times;</span>
        <p>fixed popover</p>
    </div>

    <div id="page">
        <strong>this is the top</strong><br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        lots of scrollable content<br>
        asdfasdf<br>
        <br>
        <div><a href="#">Show Popover</a></div>
        <br>
        <br>

    </div>

</body>

</html>

Benutzer-Avatar
Bohdan Diduch

Hinzufügen -webkit-overflow-scrolling: touch; zum #overlay Element.

Fügen Sie dann diesen JavaScript-Code am Ende des Body-Tags hinzu:

(function () {
  var _overlay = document.getElementById('overlay');
  var _clientY = null; // remember Y position on touch start

  _overlay.addEventListener('touchstart', function (event) {
    if (event.targetTouches.length === 1) {
      // detect single touch
      _clientY = event.targetTouches[0].clientY;
    }
  }, false);

  _overlay.addEventListener('touchmove', function (event) {
    if (event.targetTouches.length === 1) {
      // detect single touch
      disableRubberBand(event);
    }
  }, false);

  function disableRubberBand(event) {
    var clientY = event.targetTouches[0].clientY - _clientY;

    if (_overlay.scrollTop === 0 && clientY > 0) {
      // element is at the top of its scroll
      event.preventDefault();
    }

    if (isOverlayTotallyScrolled() && clientY < 0) {
      //element is at the top of its scroll
      event.preventDefault();
    }
  }

  function isOverlayTotallyScrolled() {
    // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
    return _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight;
  }
}())

  • Der Code sollte besser in einer externen Datei gespeichert werden, damit er zwischengespeichert werden kann.

    – Rolf

    10. November 2017 um 14:26 Uhr


  • Ich nehme an, derselbe Trick wird für Firefox für iOS funktionieren, das anscheinend das gleiche Problem hat?

    – Anthony Kong

    16. August 2018 um 1:59 Uhr

  • Ich muss all das js kopieren, nur um das Scrollen im Hintergrund zu deaktivieren, wenn eine Overlay-Decke oben ist? Ich hoffe es gibt eine elegantere Lösung

    – Sieger

    8. Dezember 2018 um 9:47 Uhr


  • vue mixin heiße lieferung! gist.github.com/vovchisko/7222b0270a5953a9074abb5876720a7a

    – vovchisko

    30. Juli 2019 um 11:35 Uhr


  • Wenn das Blockieren des Momentums erwünscht ist, habe ich unten einfach meine eigene Lösung hinzugefügt, beeinflusst von @BohdanDidukh 🙂 — stackoverflow.com/a/57566116/2321594

    – Hilfe bei der

    20. August 2019 um 2:52 Uhr

  • Dies ist die richtige Antwort für Safari > 13. Leider werden nicht alle Apple-Geräte aktualisiert. sondern touch-action kombiniert mit body, html { position: fixed; } scheinen vorerst zu funktionieren.

    – Brmm

    12. August 2020 um 17:14 Uhr

Wenn Ihr Overlay geöffnet ist, können Sie eine Klasse wie hinzufügen prevent-scroll zu body um das Scrollen von Elementen hinter Ihrem Overlay zu verhindern:

body.prevent-scroll {
  position: fixed;
  overflow: hidden;
  width: 100%;
  height: 100%;
}

https://codepen.io/claudiojs/pen/ZKeLvq

  • Ich befürchte, dass die Bildlaufposition nicht beibehalten wird.

    – aventisch

    3. August 2017 um 9:24 Uhr

Benutzer-Avatar
Angus Bremer

In einigen Fällen, in denen der Textinhalt hinter Ihrem Overlay verborgen ist, können Sie die aktuelle Bildlaufposition mit speichern const scrollPos = window.scrollYdann bewirb dich position: fixed; zum Körper. Wenn sich das Modell schließt, entfernen Sie die fixierte Position vom Körper und laufen Sie window.scrollTo(0, scrollPos) um die vorherige Position wiederherzustellen.

Dies war für mich die einfachste Lösung mit der geringsten Menge an Code.

  • Ich befürchte, dass die Bildlaufposition nicht beibehalten wird.

    – aventisch

    3. August 2017 um 9:24 Uhr

Kombinierte den Ansatz von Bohdan Didukh mit meinem vorherigen Ansatz, um ein einfach zu verwendendes npm-Paket zum Deaktivieren / Aktivieren von Body Scroll zu erstellen.

https://github.com/willmcpo/body-scroll-lock

Weitere Informationen zur Funktionsweise der Lösung finden Sie unter https://medium.com/jsdownunder/locking-body-scroll-for-all-devices-22def9615177

  • Ja, das funktioniert leider nicht auf mobiler Safari. Ich konnte keine echten Korrekturen für das Scrollen auf der mobilen Safari finden.

    – Jeremy Gottfried

    9. Oktober 2019 um 17:59 Uhr

  • Dieses Paket verhindert in meinem Fall, dass Modale mit fester Position auf IOS-Geräten scrollen.

    – Liam McArthur

    18. Oktober 2019 um 8:35 Uhr


  • Dieses Paket war Gold wert für mich. Tolle Arbeit @Will!

    – Hirbod

    7. August 2020 um 15:11 Uhr

1005670cookie-checkiOS 10 Safari: Scrollen hinter einem festen Overlay verhindern und Scrollposition beibehalten

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy