web-dev-qa-db-de.com

Verhindern Sie das Scrollen des Körpers, lassen Sie jedoch das Scrollen überlagern

Ich habe nach einer "Lightbox" -Lösung gesucht, die dies erlaubt, aber noch keine gefunden hat (schlagen Sie vor, wenn Sie welche wissen).

Das Verhalten, das ich neu zu erstellen versuche, entspricht dem, was Sie unter Pinterest sehen, wenn Sie auf ein Bild klicken. Die Überlagerung ist scrollbar (da sich die gesamte Überlagerung wie eine Seite oben auf einer Seite bewegt), aber der Hauptteil hinter der Überlagerung ist festgelegt.

Ich habe versucht, dies nur mit CSS zu erstellen (d. H. Eine div-Einblendung oben auf der gesamten Seite und einen Hauptteil mit overflow: hidden), verhindert jedoch nicht, dass div scrollbar ist.

Wie kann das Scrollen des Hauptteils/der Seite verhindert werden, während der Bildlauf innerhalb des Vollbild-Containers fortgesetzt wird?

355
PotatoFro

Theorie

Wenn Sie die aktuelle Implementierung der pinterest-Site betrachten (möglicherweise ändert sich dies in der Zukunft), wird beim Öffnen der Überlagerung eine noscroll-Klasse auf das body-Element angewendet und overflow: hidden festgelegt, sodass body nicht mehr scrollbar ist.

Das Overlay (das direkt erstellt wird oder bereits innerhalb der Seite sichtbar ist und über display: block sichtbar gemacht wird, macht keinen Unterschied) hat position : fixed und overflow-y: scroll, wobei top, left, right und bottom auf 0 gesetzt sind ganze Ansicht. 

Die Variable div innerhalb des Overlays befindet sich stattdessen in position: static. Dann ist die vertikale Bildlaufleiste mit diesem Element verknüpft. Dadurch ist der Inhalt scrollbar, die Überlagerung bleibt jedoch unverändert.

Wenn Sie den Zoom schließen, blenden Sie das Overlay aus (über display: none) und können es auch vollständig über Javascript entfernen (oder nur den Inhalt darin, es liegt an Ihnen, wie Sie es einfügen).

Als letzten Schritt müssen Sie auch die noscroll-Klasse zur body entfernen (damit die Überlaufeigenschaft auf ihren ursprünglichen Wert zurückgesetzt wird).


Code

Codepen Beispiel

(Es funktioniert, indem Sie das aria-hidden-Attribut der Überlagerung ändern, um es ein- und auszublenden und die Zugänglichkeit zu erhöhen).

Markup
(Schaltfläche öffnen)

<button type="button" class="open-overlay">OPEN LAYER</button>

(Schaltfläche zum Einblenden und Schließen)

<section class="overlay" aria-hidden="true">
  <div>
    <h2>Hello, I'm the overlayer</h2>
    ...   
    <button type="button" class="close-overlay">CLOSE LAYER</button>
  </div>
</section>

CSS

.noscroll { 
  overflow: hidden;
}

.overlay { 
   position: fixed; 
   overflow-y: scroll;
   top: 0; right: 0; bottom: 0; left: 0; }

[aria-hidden="true"]  { display: none; }
[aria-hidden="false"] { display: block; }

Javascript _ ​​(Vanilla-JS)

var body = document.body,
    overlay = document.querySelector('.overlay'),
    overlayBtts = document.querySelectorAll('button[class$="overlay"]');

[].forEach.call(overlayBtts, function(btt) {

  btt.addEventListener('click', function() { 

     /* Detect the button class name */
     var overlayOpen = this.className === 'open-overlay';

     /* Toggle the aria-hidden state on the overlay and the 
        no-scroll class on the body */
     overlay.setAttribute('aria-hidden', !overlayOpen);
     body.classList.toggle('noscroll', overlayOpen);

     /* On some mobile browser when the overlay was previously
        opened and scrolled, if you open it again it doesn't 
        reset its scrollTop property */
     overlay.scrollTop = 0;

  }, false);

});

Zum Schluss noch ein Beispiel, in dem die Überlagerung mit einem Einblendeffekt durch eine CSS-Variable transition geöffnet wird, die auf die opacity-Eigenschaft angewendet wird. Außerdem wird ein padding-right angewendet, um einen Reflow des zugrunde liegenden Textes zu vermeiden, wenn die Bildlaufleiste ausgeblendet wird.

Codepen-Beispiel (fade)

CSS

.noscroll { overflow: hidden; }

@media (min-device-width: 1025px) {
    /* not strictly necessary, just an experiment for 
       this specific example and couldn't be necessary 
       at all on some browser */
    .noscroll { 
        padding-right: 15px;
    }
}

.overlay { 
     position: fixed; 
     overflow-y: scroll;
     top: 0; left: 0; right: 0; bottom: 0;
}

[aria-hidden="true"] {    
    transition: opacity 1s, z-index 0s 1s;
    width: 100vw;
    z-index: -1; 
    opacity: 0;  
}

[aria-hidden="false"] {  
    transition: opacity 1s;
    width: 100%;
    z-index: 1;  
    opacity: 1; 
}
542
fcalderan

Wenn Sie das Überscrolling von ios verhindern möchten, können Sie Ihrer .noscroll-Klasse eine feste Position hinzufügen

body.noscroll{
    position:fixed;
    overflow:hidden;
}
67
am80l

Verwenden Sie overflow: hidden; nicht für body. Es scrollt automatisch alles nach oben. Es gibt auch keine Notwendigkeit für JavaScript. Verwenden Sie overflow: auto;. Diese Lösung funktioniert sogar mit mobilem Safari:

HTML-Struktur

<div class="overlay">
    <div class="overlay-content"></div>
</div>

<div class="background-content">
    lengthy content here
</div>

Styling

.overlay{
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    background-color: rgba(0, 0, 0, 0.8);

    .overlay-content {
        height: 100%;
        overflow: scroll;
    }
}

.background-content{
    height: 100%;
    overflow: auto;
}

Siehe die Demo hier und den Quellcode hier .

Update:

Für Benutzer, die die Leertaste der Tastatur verwenden möchten, blättern Sie nach oben/unten, um zu funktionieren: Sie müssen sich auf die Überlagerung konzentrieren, z. B. darauf klicken oder manuell auf JS fokussieren, bevor dieser Teil der div auf die Tastatur reagiert. Das Gleiche gilt für den Fall, dass das Overlay "ausgeschaltet" ist, da es nur das Overlay zur Seite bewegt. Ansonsten für Browser sind dies nur zwei normale divs und sie wissen nicht, warum sie sich auf einen von ihnen konzentrieren sollten.

36
Luxiyalu

Es ist erwähnenswert, dass manchmal das Hinzufügen von "overflow: hidden" zum body-Tag die Aufgabe nicht erfüllt. In diesen Fällen müssen Sie die Eigenschaft auch dem html-Tag hinzufügen.

html, body {
    overflow: hidden;
}
28
Francisco Hodge

Die meisten Lösungen haben das Problem, dass sie die Bildlaufposition nicht beibehalten. Daher habe ich mir angesehen, wie Facebook dies tut. Zusätzlich zum Festlegen des zugrunde liegenden Inhalts auf position: fixed wird der obere Rand dynamisch festgelegt, um die Bildlaufposition beizubehalten:

scrollPosition = window.pageYOffset;
mainEl.style.top = -scrollPosition + 'px';

Wenn Sie dann das Overlay wieder entfernen, müssen Sie die Bildlaufposition zurücksetzen:

window.scrollTo(0, scrollPosition);

Ich habe ein kleines Beispiel erstellt, um diese Lösung zu demonstrieren

let overlayShown = false;
let scrollPosition = 0;

document.querySelector('.toggle').addEventListener('click', function() {
  if (overlayShown) {
		showOverlay();
  } else {
    removeOverlay();
  }
  overlayShown = !overlayShown;
});

function showOverlay() {
    scrollPosition = window.pageYOffset;
  	const mainEl = document.querySelector('.main-content');
    mainEl.style.top = -scrollPosition + 'px';
  	document.body.classList.add('show-overlay');
}

function removeOverlay() {
		document.body.classList.remove('show-overlay');
  	window.scrollTo(0, scrollPosition);
    const mainEl = document.querySelector('.main-content');
    mainEl.style.top = 0;
}
.main-content {
  background-image: repeating-linear-gradient( Lime, blue 103px);
  width: 100%;
  height: 200vh;
}

.show-overlay .main-content {
  position: fixed;
  left: 0;
  right: 0;
  overflow-y: scroll; /* render disabled scroll bar to keep the same width */
}

.overlay {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.3);
  overflow: auto;
}

.show-overlay .overlay {
  display: block;
}

.overlay-content {
  margin: 50px;
  background-image: repeating-linear-gradient( grey, grey 20px, black 20px, black 40px);
  height: 120vh;
}

.toggle {
  position: fixed;
  top: 5px;
  left: 15px;
  padding: 10px;
  background: red;
}

/* reset CSS */
body {
  margin: 0;
}
<main class="main-content"></main>

  <div class="overlay">
    <div class="overlay-content"></div>
  </div>
  
  <button class="toggle">Overlay</button>

22

Die overscroll-behavior css-Eigenschaft ermöglicht das Überschreiben des standardmäßigen Überlaufbildlaufs des Browsers, wenn der Inhalt oben oder unten erreicht wird.

Fügen Sie einfach die folgenden Stile zur Überlagerung hinzu:

.overlay {
   overscroll-behavior: contain;
   ...
}

Codepen Demo

Funktioniert derzeit in Chrome, Firefox und IE ( caniuse )

Weitere Informationen finden Sie im google-Entwicklerartikel .

18
Igor Alemasow

Die gewählte Antwort ist korrekt, hat aber einige Einschränkungen:

  • Super harte "Schleudern" mit dem Finger rollen immer noch <body> Im Hintergrund
  • Wenn Sie die virtuelle Tastatur öffnen, indem Sie im Modal auf <input> Tippen, werden alle zukünftigen Bildläufe zu <body> Geleitet.

Ich habe keine Lösung für das erste Problem, wollte aber etwas Licht in das zweite bringen. Verwirrenderweise hatte Bootstrap das Tastaturproblem dokumentiert, aber sie behaupteten, es sei behoben, unter Berufung auf http://output.jsbin.com/cacido/quiet als Beispiel für das Update.

In der Tat funktioniert dieses Beispiel unter iOS mit meinen Tests einwandfrei. Ein Upgrade auf die neueste Version von Bootstrap (v4)) führt jedoch zum Absturz.

Um herauszufinden, was der Unterschied zwischen ihnen ist, habe ich einen Testfall so reduziert, dass er nicht mehr von Bootstrap abhängt, http://codepen.io/WestonThayer/pen/bgZxBG .

Die entscheidenden Faktoren sind bizarr. Um das Tastaturproblem zu vermeiden, muss anscheinend background-color ist nicht im Stammverzeichnis <div> Eingestellt sein, das das Modal und des Modals enthält Inhalt muss in einem anderen <div> verschachtelt sein, für den background-color festgelegt werden kann.

Kommentieren Sie zum Testen die folgende Zeile im Codepen-Beispiel aus:

.modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  display: none;
  overflow: hidden;
  -webkit-overflow-scrolling: touch;
  /* UNCOMMENT TO BREAK */
/*   background-color: white; */
}
7
Weston

Wenn Sie möchten, dass ein übergeordnetes Element (in diesem Fall der Hauptteil) einen Bildlauf durch ein untergeordnetes Objekt (in diesem Fall die Überlagerung) verhindert, müssen Sie das untergeordnete Element des übergeordneten Objekts festlegen, um zu verhindern, dass das Bildlaufereignis sprudelt das Elternteil. Wenn der übergeordnete Körper der Körper ist, erfordert dies ein zusätzliches Umhüllungselement:

<div id="content">
</div>
<div id="overlay">
</div>

Siehe Scrollen Sie zu bestimmten DIV-Inhalten mit der Haupt-Scrollleiste des Browsers , um die Funktionsweise zu sehen.

6
NGLN

Fügen Sie bei Touch-Geräten einen 1px breiten, 101vh min-height transparenten div im Wrapper des Overlays hinzu. Fügen Sie dem Wrapper dann -webkit-overflow-scrolling:touch; overflow-y: auto; hinzu. Dies führt dazu, dass die mobile Safari den Eindruck erweckt, dass die Überlagerung scrollbar ist, wodurch das Berührungsereignis vom Körper abgefangen wird.

Hier ist eine Beispielseite. Offen für mobile Safari: http://www.originalfunction.com/overlay.html

https://Gist.github.com/YarGnawh/90e0647f21b5fa78d2f678909673507f

4
YarGnawh

Ich stellte fest, dass diese Frage versucht wurde, ein Problem zu lösen, das ich mit meiner Seite auf dem Ipad hatte.

Einige Antworten sind gut, aber keine von ihnen löste mein Problem. Ich habe folgenden Blog-Beitrag von Christoffer Pettersson gefunden. Die dort präsentierte Lösung half bei Problemen mit iOS-Geräten und half beim Scrollen des Hintergrunds. 

Sechs Dinge, die ich über das Scrollen durch iOS-Safari gelernt habe

Wie vorgeschlagen wurde, füge ich wichtige Punkte des Blogposts hinzu, falls der Link nicht mehr aktuell ist. 

"Um zu deaktivieren, dass der Benutzer die Hintergrundseite scrollen kann, während das Menü geöffnet ist, ist es möglich, zu steuern, welche Elemente gescrollt werden dürfen oder nicht, indem JavaScript und eine CSS - Klasse angewendet werden.

Basierend auf dieser Stackoverflow - Antwort können Sie steuern, dass Elemente mit dem Bildlauf-Deaktivieren keine Ihre Standard-Scroll-Aktion ausführen sollen, wenn das Touchmove-Ereignis ausgelöst wird.

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

Und dann setzen Sie die Disable-Scrolling-Klasse auf das Seiten-Div:

<div class="page disable-scrolling">
3

Ich möchte gerne die vorherigen Antworten hinzufügen, da ich dies versucht habe. Sobald das Gehäuse in Position gebracht wurde, brach etwas Layout: behoben. Um das zu vermeiden, musste ich auch die Körpergröße auf 100% einstellen:

function onMouseOverOverlay(over){
    document.getElementsByTagName("body")[0].style.overflowY = (over?"hidden":"scroll");
    document.getElementsByTagName("html")[0].style.position = (over?"fixed":"static");
    document.getElementsByTagName("html")[0].style.height = (over?"100%":"auto");
}
1

Verwenden Sie den folgenden HTML-Code:

<body>
  <div class="page">Page content here</div>
  <div class="overlay"></div>
</body>

Dann JavaScript abfangen und Scrollen stoppen:

$(".page").on("touchmove", function(event) {
  event.preventDefault()
});

Dann, um die Dinge wieder normal zu machen:

$(".page").off("touchmove");

1
Damir Kotoric

Wenn Sie den Body/HTML-Scroll stoppen möchten, fügen Sie Folgendes hinzu:

CSS

    html, body {
        height: 100%;
    }

    .overlay{
        position: fixed;
        top: 0px;
        left: 0px;
        right: 0px;
        bottom: 0px;
        background-color: rgba(0, 0, 0, 0.8);

        .overlay-content {
            height: 100%;
            overflow: scroll;
        }
    }

    .background-content{
        height: 100%;
        overflow: auto;
    }

HTML

    <div class="overlay">
        <div class="overlay-content"></div>
    </div>

    <div class="background-content">
        lengthy content here
    </div>

Grundsätzlich könnte man es ohne JS machen.

Die Hauptidee ist, html/body mit height: 100% und overflow: auto . Hinzuzufügen. Innerhalb Ihres Overlays können Sie den Bildlauf je nach Anforderung aktivieren/deaktivieren.

Hoffe das hilft!

0
Ashwin

Wenn auf mobilen Geräten/Touch-Geräten die Deaktivierung beabsichtigt ist, verwenden Sie touch-action: none; am einfachsten.

Beispiel:

const app = document.getElementById('app');
const overlay = document.getElementById('overlay');

let body = '';

for (let index = 0; index < 500; index++) {
  body += index + '<br />';
}

app.innerHTML = body;
app.scrollTop = 200;

overlay.innerHTML = body;
* {
  margin: 0;
  padding: 0;
}

html,
body {
  height: 100%;
}

#app {
  background: #f00;
  position: absolute;
  height: 100%;
  width: 100%;
  overflow-y: scroll;
  line-height: 20px;
}

#overlay {
  background: rgba(0,0,0,.5);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 100%;
  padding: 0 0 0 100px;
  overflow: scroll;
}
<div id='app'></div>
<div id='overlay'></div>

(Das Beispiel funktioniert nicht im Zusammenhang mit Stack Overflow. Sie müssen es auf einer eigenständigen Seite neu erstellen.)

Wenn Sie das Scrollen des #app-Containers deaktivieren möchten, fügen Sie einfach touch-action: none; hinzu.

0
Gajus

Das Verhalten, das Sie verhindern möchten, wird als Scroll-Verkettung bezeichnet. Um es zu deaktivieren, setzen Sie

overscroll-behavior: contain;

auf Ihrem Overlay in CSS.

0
黄雨伞

versuche dies

var mywindow = $('body'), navbarCollap = $('.navbar-collapse');    
navbarCollap.on('show.bs.collapse', function(x) {
                mywindow.css({visibility: 'hidden'});
                $('body').attr("scroll","no").attr("style", "overflow: hidden");
            });
            navbarCollap.on('hide.bs.collapse', function(x) {
                mywindow.css({visibility: 'visible'});
                $('body').attr("scroll","yes").attr("style", "");
            });
0
Junaid