Zapobiegaj przewijaniu ciała, ale Zezwalaj na przewijanie nakładek

Szukałem rozwiązania typu "lightbox", które na to pozwala, ale jeszcze nie znalazłem (proszę, sugeruj, jeśli znasz jakieś).

Zachowanie, które próbuję odtworzyć, jest podobne do tego, co można zobaczyć na Pintereście po kliknięciu obrazu. Nakładka jest przewijalna (ponieważ cała nakładka porusza się w górę jak strona na górze strony), ale ciało ZA nakładka jest stała.

Próbowałem stworzyć to za pomocą CSS ( tj. nakładki div na górze całej strony i body z overflow: hidden), ale nie uniemożliwia div przewijania.

Jak zachować treść / stronę przed przewijaniem, ale nadal przewijać wewnątrz kontenera pełnoekranowego?

Author: Konstantin Grushetsky, 2012-02-14

17 answers

Teoria

Patrząc na bieżącą implementację witryny Pinteresta (może się ona zmienić w przyszłości), po otwarciu nakładki do elementu body zostanie zastosowana Klasa noscroll, a overflow: hidden zostanie ustawiona, więc body nie będzie już można przewijać.

Nakładka (tworzona w locie lub już wewnątrz strony i widoczna przez display: block, nie robi różnicy) ma position : fixed i overflow-y: scroll, z top, left, right i bottom właściwości ustawione na 0: ten styl sprawia, że nakładka wypełnij cały widok.

div wewnątrz nakładki jest zamiast tego tylko w position: static wtedy pionowy pasek przewijania, który widzisz, jest powiązany z tym elementem. W rezultacie zawartość jest przewijana, ale nakładka pozostaje stała.

Po zamknięciu zoomu ukrywasz nakładkę (za pomocą display: none), a następnie możesz ją całkowicie usunąć za pomocą javascript (lub tylko zawartość wewnątrz, od Ciebie zależy, jak ją wstrzyknąć).

Jako ostatni krok musisz również usunąć noscroll klasę do body (tak więc właściwość overflow powraca do swojej wartości początkowej)


Kod

Przykład Codepen

(działa poprzez zmianę atrybutu aria-hidden nakładki w celu pokazania i ukrycia jej oraz zwiększenia jej dostępności).

Znaczniki
(Otwórz przycisk)

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

(nakładka i przycisk zamykania)

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

});

Wreszcie, oto kolejny przykład, w którym nakładka otwiera się z efektem zanikania przez CSS transition zastosowany do właściwości opacity. Stosuje się również znak padding-right, aby uniknąć ponownego wlewu tekstu, Gdy pasek przewijania zniknie.

Przykład Codepen (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; 
}
 515
Author: fcalderan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-27 08:18:41

Jeśli chcesz zapobiec overscrollingowi na ios, możesz dodać pozycję stałą do swojego.Klasa noscroll

body.noscroll{
    position:fixed;
    overflow:hidden;
}
 63
Author: am80l,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-17 07:54:36

Nie używaj overflow: hidden; na body. Automatycznie przewija wszystko do góry. JavaScript też nie jest potrzebny. Wykorzystaj overflow: auto;. To rozwiązanie działa nawet z mobilnym Safari:

Struktura HTML

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

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

Stylizacja

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

Zobacz demo tutaj oraz kod źródłowy tutaj.

Update:

Dla osób, które chcą spacji na klawiaturze, strona w górę/w dół do pracy: musisz skupić się na nakładce, np. klikając na nią, lub ręcznie JS skupiając się na nim, zanim ta część div odpowie na klawiaturę. To samo dotyczy sytuacji, gdy nakładka jest "wyłączona", ponieważ po prostu przesuwa nakładkę na bok. W przeciwnym razie do przeglądarki, są to tylko dwa normalne divs i nie wiedziałby, dlaczego powinien skupić się na którejkolwiek z nich.

 33
Author: Luxiyalu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-31 06:47:06

Warto zauważyć, że czasami dodanie "overflow:hidden" do tagu body nie sprawdza się. W takich przypadkach będziesz musiał dodać właściwość do znacznika html.

html, body {
    overflow: hidden;
}
 28
Author: Francisco Hodge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-18 19:58:24

Większość rozwiązań ma problem, że nie zachowują pozycji przewijania, więc przyjrzałem się, jak Facebook to robi. Oprócz Ustawienia zawartości podkładu na position: fixed ustawiają również dynamicznie górę, aby zachować pozycję przewijania:

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

Następnie, po ponownym usunięciu nakładki, musisz zresetować pozycję przewijania:

window.scrollTo(0, scrollPosition);

Stworzyłem mały przykład, aby zademonstrować to rozwiązanie

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;
}
  <main class="main-content"></main>

  <div class="overlay">
    <div class="overlay-content"></div>
  </div>
  
  <button class="toggle">Overlay</button>
 17
Author: Philipp Mitterer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-21 06:38:28

overscroll-behavior właściwość css pozwala nadpisać domyślne zachowanie przewijania przepełnienia przeglądarki po osiągnięciu górnej / dolnej części zawartości.

Wystarczy dodać następujące style do nakładki:

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

Codepen demo

Obecnie działa w Chrome, Firefox i IE (caniuse )

Aby uzyskać więcej informacji sprawdź artykuł programistów google.

 13
Author: Igor Alemasow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-04 11:07:58

Ogólnie rzecz biorąc, jeśli chcesz, aby rodzic (ciało w tym przypadku) zapobiegał przewijaniu podczas przewijania dziecka (nakładka w tym przypadku), zmień dziecko na rodzeństwo rodzica, aby zapobiec przewijaniu zdarzenia do rodzica. W przypadku, gdy rodzicem jest ciało, wymaga to dodatkowego elementu owijania:

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

Zobacz przewiń zawartość DIV za pomocą głównego paska przewijania przeglądarki, aby zobaczyć jego działanie.

 5
Author: NGLN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:35

Wybrana odpowiedź jest poprawna, ale ma pewne ograniczenia:

  • Super twarde "rzuty" palcem nadal będą przewijać <body> w tle
  • otwarcie wirtualnej klawiatury przez naciśnięcie <input> w modalu spowoduje skierowanie wszystkich przyszłych zwojów do <body>

Nie mam poprawki dla pierwszego wydania, ale chciałem rzucić trochę światła na drugi. Co mylące, Bootstrap miał udokumentowany problem z klawiaturą, ale twierdzili, że został naprawiony, powołując się na http://output.jsbin.com/cacido/quiet jako przykład poprawki.

Rzeczywiście, ten przykład działa dobrze na iOS z moimi testami. Jednak aktualizacja go do najnowszej wersji Bootstrap (v4) powoduje jego uszkodzenie.

Próbując dowiedzieć się, jaka była różnica między nimi, zmniejszyłem przypadek testowy, aby nie zależał już od Bootstrap, http://codepen.io/WestonThayer/pen/bgZxBG .

Czynniki decydujące są dziwaczne. Unikanie problemu z klawiaturą wydaje się wymagać, że background-color nie jest ustawione na korzeniu <div> zawierającym modal i zawartość modalu musi być zagnieżdżona w innym <div>, który może mieć background-color ustawiony.

Aby go przetestować, odkomentuj poniższy wiersz w przykładzie Codepen:

.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; */
}
 5
Author: Weston,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-15 20:25:12

Dla urządzeń dotykowych, spróbuj dodać przezroczysty div o szerokości 1px, 101vh min wysokości w opakowaniu nakładki. Następnie dodaj -webkit-overflow-scrolling:touch; overflow-y: auto; do opakowania. To zmusza mobile safari do myślenia, że nakładka jest przewijalna, przechwytując w ten sposób Zdarzenie dotykowe z ciała.

Oto przykładowa strona. Otwórz w mobilnym safari: http://www.originalfunction.com/overlay.html

Https://gist.github.com/YarGnawh/90e0647f21b5fa78d2f678909673507f

 4
Author: YarGnawh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-25 07:52:10

Znalazłem to pytanie, próbując rozwiązać problem, który miałem z mojej strony na iPadzie i Iphone-ciało było przewijanie, gdy wyświetlał stałe div jako popup z obrazem.

Niektóre odpowiedzi są dobre, jednak żadna z nich nie rozwiązała mojego problemu. Znalazłem następujący wpis na blogu Christoffer Pettersson. Przedstawione tam rozwiązanie pomogło problemowi z urządzeniami z systemem iOS i pomogło mojemu problemowi z przewijaniem tła.

Sześć rzeczy, których się nauczyłem o przewijaniu gumki iOS Safari

Jak to sugerowano, że dołączam główne punkty postu na blogu w przypadku, gdy link się nieaktualizuje.

"aby wyłączyć możliwość przewijania strony w tle podczas "menu jest otwarte", można kontrolować, które elementy powinny być przewijane, stosując niektóre JavaScript i klasę CSS.

Na podstawie odpowiedzi Stackoverflow można kontrolować, że elementy z wyłączonym przewijaniem nie powinny wykonaj domyślną akcję przewijania podczas zdarzenia touchmove jest uruchomiony."

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

A następnie umieść klasę disable-scrolling na stronie div:

<div class="page disable-scrolling">
 3
Author: TheFullResolution,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:45

Chciałbym dodać do poprzednich odpowiedzi, ponieważ próbowałem to zrobić, a jakiś layout się zepsuł, gdy tylko zmieniłem ciało na position: fixed. Aby tego uniknąć, musiałem również ustawić wysokość ciała na 100%: {]}

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
Author: Vic Seedoubleyew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-08 08:52:36

Użyj następującego kodu HTML:

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

Następnie JavaScript, aby przechwycić i zatrzymać przewijanie:

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

Potem żeby wszystko wróciło do normy:

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

 1
Author: Damir Kotoric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-09 11:45:44

Zachowanie, któremu chcesz zapobiec nazywa się scroll chaining. Aby go wyłączyć, Ustaw

overscroll-behavior: contain;

Na Twojej nakładce w CSS.

 1
Author: 黄雨伞,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-24 14:23:12

Jeśli intencją jest wyłączenie na urządzeniach mobilnych/ dotykowych, najprostszym sposobem jest użycie touch-action: none;.

Przykład:

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>

(przykład nie działa w kontekście przepełnienia stosu. Będziesz musiał odtworzyć go na samodzielnej stronie.)

Jeśli chcesz wyłączyć przewijanie kontenera #app, po prostu dodaj touch-action: none;.

 0
Author: Gajus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-22 13:06:34

Spróbuj tego

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
Author: Junaid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 13:23:57

W moim przypadku żadne z tych rozwiązań nie zadziałało na iPhonie (iOS 11.0).

Jedyną skuteczną poprawką, która działa na wszystkich moich urządzeniach, jest Ta - IOS-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-position

 -1
Author: potar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-22 13:17:12

Użyj poniższego kodu, aby wyłączyć i włączyć pasek przewijania.

Scroll = (
    function(){
          var x,y;
         function hndlr(){
            window.scrollTo(x,y);
            //return;
          }  
          return {

               disable : function(x1,y1){
                    x = x1;
                    y = y1;
                   if(window.addEventListener){
                       window.addEventListener("scroll",hndlr);
                   } 
                   else{
                        window.attachEvent("onscroll", hndlr);
                   }     

               },
               enable: function(){
                      if(window.removeEventListener){
                         window.removeEventListener("scroll",hndlr);
                      }
                      else{
                        window.detachEvent("onscroll", hndlr);
                      }
               } 

          }
    })();
 //for disabled scroll bar.
Scroll.disable(0,document.body.scrollTop);
//for enabled scroll bar.
Scroll.enable();
 -2
Author: Rakesh Chaudhari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-20 15:37:52