Po prostu wyłącz przewijanie, a nie ukryć?

198

Próbuję wyłączyć pasek przewijania html / body rodzica, gdy korzystam z lightbox. Głównym słowem tutaj jest „ wyłącz” . Ja nie chce go ukryć overflow: hidden;.

Powodem tego jest to, overflow: hiddenże strona przeskakuje i zajmuje obszar, w którym znajdował się zwój.

Chcę wiedzieć, czy można wyłączyć pasek przewijania, wciąż go wyświetlając.

Dejan.S
źródło
1
Czy powinno być możliwe przewijanie? (Czy lightbox ma jakieś paski przewijania?)
Šime Vidas
strona się przewijała, ale chcę ją tylko wyłączyć, gdy lightbox jest otwarty. Chcę tylko wiedzieć, czy można wyłączyć pasek przewijania podczas jego wyświetlania. nic więcej nie jest potrzebne, jak to zrobić w lightboxie lub cokolwiek innego.
Dejan.S
na czym polega problem przy użyciu lightbox z paskiem przewijania?
manny
1
@Dejan Ponieważ wiem, jak wyłączyć wszystkie przewijanie - to wyłączałoby główny pasek przewijania, ale także ten w lightbox ...
Šime Vidas
1
Nie edytuj odpowiedzi z powrotem w tym poście. Poniższa sekcja odpowiedzi zawiera odpowiedzi. Jeśli masz odpowiedź na swoje pytanie inną niż odpowiedź poniżej, możesz dodać własne rozwiązanie w wyborze odpowiedzi.
intcreator

Odpowiedzi:

172

Jeśli stronę pod nakładką można „naprawić” u góry, po otwarciu nakładki można ustawić

body { position: fixed; overflow-y:scroll }

powinieneś nadal widzieć prawy pasek przewijania, ale zawartość nie jest przewijana. Po zamknięciu nakładki po prostu przywróć te właściwości za pomocą

body { position: static; overflow-y:auto }

Właśnie zaproponowałem ten sposób tylko dlatego, że nie trzeba zmieniać żadnego zdarzenia przewijania

Aktualizacja

Możesz także wprowadzić niewielką poprawę: jeśli uzyskasz document.documentElement.scrollTopwłaściwość za pomocą javascript tuż przed otwarciem warstwy, możesz dynamicznie przypisać tę wartość jako topwłaściwość elementu body: dzięki takiemu podejściu strona pozostanie na swoim miejscu, bez względu na to, czy „ ponownie na górze lub jeśli już przewinąłeś.

Css

.noscroll { position: fixed; overflow-y:scroll }

JS

$('body').css('top', -(document.documentElement.scrollTop) + 'px')
         .addClass('noscroll');
Fabrizio Calderan
źródło
2
zadziera z moim układem, ale z pewnymi modyfikacjami może po prostu działać. podoba mi się to, wypróbuję więcej
Dejan.S
4
z niewielką modyfikacją to działa. dodałem szerokość: 100%; ode mnie zaktualizowałem moje pytanie o rozwiązanie, ale możesz je zmienić o szerokości: 100% ;? dzięki za sugestię
Dejan.S.
3
Nie wiem dlaczego, ale to działa dla mnie lepiej: $('body').css('top', -($('body').scrollTop()) + 'px').addClass('noscroll');
PDXIII
4
@whitesiroi, masz rację. Zaktualizowałem skrzypce: jsfiddle.net/evpozdniakov/2m8km9wg Dziękujemy!
evpozdniakov
1
Dla tych, którzy czytają komentarze do rozwiązania, ostatnie skrzypce zapewnia rozwiązanie umożliwiające wyłączenie i ponowne włączenie paska przewijania przy jednoczesnym zachowaniu pozycji paska przewijania w obu przypadkach. Dzięki!
user1063287,
78

Cztery małe dodatki do wybranego rozwiązania:

  1. Zastosuj „noscroll” do html zamiast do body, aby zapobiec podwójnym paskom przewijania w IE
  2. Aby sprawdzić, czy rzeczywiście istnieje pasek przewijania przed dodaniem klasy „noscroll”. W przeciwnym razie witryna również przeskoczy przez nowy, nieprzewijający pasek przewijania.
  3. Aby zachować jak to możliwe scrollTop, aby cała strona nie wróciła na górę (jak aktualizacja Fabrizio, ale musisz pobrać wartość przed dodaniem klasy „noscroll”)
  4. Nie wszystkie przeglądarki obsługują scrollTop w taki sam sposób, jak udokumentowano w http://help.dottoro.com/ljnvjiow.php

Kompletne rozwiązanie, które wydaje się działać w większości przeglądarek:

CSS

html.noscroll {
    position: fixed; 
    overflow-y: scroll;
    width: 100%;
}

Wyłącz przewijanie

if ($(document).height() > $(window).height()) {
     var scrollTop = ($('html').scrollTop()) ? $('html').scrollTop() : $('body').scrollTop(); // Works for Chrome, Firefox, IE...
     $('html').addClass('noscroll').css('top',-scrollTop);         
}

Włącz przewijanie

var scrollTop = parseInt($('html').css('top'));
$('html').removeClass('noscroll');
$('html,body').scrollTop(-scrollTop);

Dzięki Fabrizio i Dejanowi za postawienie mnie na właściwej drodze, a Brodingo za rozwiązanie podwójnego paska przewijania

Mike Garcia
źródło
1
Sprawdził się dobrze na komputerze, ale na iPhonie stworzył pusty biały ekran, dopóki czytelnik nie próbował przewinąć strony. Gdy czytelnik próbował wejść w interakcję ze stroną, zamierzony ekran stał się widoczny przy zablokowanym przewijaniu.
Michael Khalili
Działa to doskonale z Fancybox na iPadzie, aby wyłączyć przewijanie obrazu lightbox afterLoad()i afterClosewywołań zwrotnych. Może być przydatny dla innych osób szukających tego pytania.
Tomanow
W części „Włącz przewijanie” możesz chcieć usunąć atrybut stylu, który jest umieszczony na elemencie HTML po wywołaniu „Wyłącz przewijanie”; nie ty
Ben,
3
jQuery standaryzuje rodzime DOM, scrollToptak że wiersz 2 kodu „Wyłącz przewijanie” może być wyrażony jako $( window ).scrollTop().
Barney,
Myślę, że należy do tego dodać jeszcze jedną rzecz. W Chrome w OSX przeglądarka może „przewijać”, zapewniając elastyczne przewijanie. Z tym kodem, jeśli znajdujesz się w szarym obszarze powyżej lub poniżej strony i najeżdżasz wskaźnikiem myszy na miejsce, w którym wyłączasz przewijanie. Przylgnie do miejsca powyżej / poniżej okna przeglądarki. Z tego powodu trzeba dodać czek na ujemną wartość przewijania: if (scrollTop < 0) { scrollTop = 0; }. Oto pełny kod wyłączający gist.github.com/jayd3e/2eefbbc571cd1668544b .
JayD3e,
34

Z dołączonym jQuery:


wyłączyć

$.fn.disableScroll = function() {
    window.oldScrollPos = $(window).scrollTop();

    $(window).on('scroll.scrolldisabler',function ( event ) {
       $(window).scrollTop( window.oldScrollPos );
       event.preventDefault();
    });
};

włączyć

$.fn.enableScroll = function() {
    $(window).off('scroll.scrolldisabler');
};

stosowanie

//disable
$("#selector").disableScroll();
//enable
$("#selector").enableScroll();
ceed
źródło
1
to było dla mnie idealne, poprzednia odpowiedź sprawiła, że ​​moja strona odskoczyła, a ta nie
Bogdan Tomi
Cieszę się, że mogłem pomóc, być może trzeba też sprawdzić „touchmove”, na urządzeniach mobilnych, na zdrowie
ceed
Cóż, to prawie dla mnie zadziałało. Działa cuda w systemach Windows (Firefox, Chrome) i MacOS w Firefox ... ale potem przeszedłem do Windows IE i Edge, wraz z MacOS w Chrome i Safari. Problem nie polegał już na przeskakiwaniu strony z boku na bok, ale pasek przewijania przeskakiwał z góry do bieżącej pozycji lub strona migała do góry. Człowieku, to było tak , tak blisko. Może nadal możemy sprawić, że to zadziała.
Steven Ventimiglia
Działa to dla mnie idealnie, dziękuję! Idealny do użycia na stronie internetowej, w której menu nakładki znajduje się również na dole strony!
SauriolJf
12

Jestem OP

Dzięki pomocy fcalderan udało mi się stworzyć rozwiązanie. Zostawiam tutaj moje rozwiązanie, ponieważ zapewnia przejrzystość sposobu jego używania i dodaje bardzo ważny szczegół,width: 100%;

Dodaję tę klasę

body.noscroll
{
    position: fixed; 
    overflow-y: scroll;
    width: 100%;
}

to działało dla mnie i korzystałem z Fancyapp.

Dejan.S
źródło
11

To działało naprawdę dobrze dla mnie ....

// disable scrolling
$('body').bind('mousewheel touchmove', lockScroll);

// enable scrolling
$('body').unbind('mousewheel touchmove', lockScroll);


// lock window scrolling
function lockScroll(e) {
    e.preventDefault();
}

po prostu owiń te dwa wiersze kodu tym, co decyduje o tym, kiedy zamierzasz zablokować przewijanie.

na przykład

$('button').on('click', function() {
     $('body').bind('mousewheel touchmove', lockScroll);
});
dmackenz
źródło
To najlepsza odpowiedź spośród nich wszystkich
Jafo,
7

Nie można wyłączyć zdarzenia przewijania, ale można wyłączyć powiązane akcje prowadzące do przewijania, takie jak kółko myszy i ruch dotykowy:

$('body').on('mousewheel touchmove', function(e) {
      e.preventDefault();
});
tocqueville
źródło
4

Możesz ukryć pasek przewijania ciała za pomocą overflow: hidden i jednocześnie ustawić margines, aby zawartość nie przeskakiwała:

let marginRightPx = 0;
if(window.getComputedStyle) {
    let bodyStyle = window.getComputedStyle(document.body);
    if(bodyStyle) {
        marginRightPx = parseInt(bodyStyle.marginRight, 10);
    }
}

let scrollbarWidthPx = window.innerWidth - document.body.clientWidth;
Object.assign(document.body.style, {
    overflow: 'hidden',
    marginRight: `${marginRightPx + scrollbarWidthPx}px`
});

Następnie możesz dodać wyłączony pasek przewijania do strony, aby wypełnić lukę:

textarea {
  overflow-y: scroll;
  overflow-x: hidden;
  width: 11px;
  outline: none;
  resize: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  border: 0;
}
<textarea></textarea>

Zrobiłem dokładnie to dla mojej własnej implementacji lightbox. Wygląda na to, że do tej pory działał dobrze.

mpen
źródło
1
Najbardziej podoba mi się ta metoda. Bardzo prosty i działa świetnie. Dzięki!
dericcain
2

To jest rozwiązanie, z którym poszliśmy. Po prostu zapisz pozycję przewijania po otwarciu nakładki, przewiń z powrotem do zapisanej pozycji za każdym razem, gdy użytkownik spróbuje przewinąć stronę, i wyłącz słuchacza po zamknięciu nakładki.

W IE jest nieco przesadzony, ale działa jak urok w Firefox / Chrome.

var body = $("body"),
  overlay = $("#overlay"),
  overlayShown = false,
  overlayScrollListener = null,
  overlaySavedScrollTop = 0,
  overlaySavedScrollLeft = 0;

function showOverlay() {
  overlayShown = true;

  // Show overlay
  overlay.addClass("overlay-shown");

  // Save scroll position
  overlaySavedScrollTop = body.scrollTop();
  overlaySavedScrollLeft = body.scrollLeft();

  // Listen for scroll event
  overlayScrollListener = body.scroll(function() {
    // Scroll back to saved position
    body.scrollTop(overlaySavedScrollTop);
    body.scrollLeft(overlaySavedScrollLeft);
  });
}

function hideOverlay() {
  overlayShown = false;

  // Hide overlay
  overlay.removeClass("overlay-shown");

  // Turn scroll listener off
  if (overlayScrollListener) {
    overlayScrollListener.off();
    overlayScrollListener = null;
  }
}

// Click toggles overlay
$(window).click(function() {
  if (!overlayShown) {
    showOverlay();
  } else {
    hideOverlay();
  }
});
/* Required */
html, body { margin: 0; padding: 0; height: 100%; background: #fff; }
html { overflow: hidden; }
body { overflow-y: scroll; }

/* Just for looks */
.spacer { height: 300%; background: orange; background: linear-gradient(#ff0, #f0f); }
.overlay { position: fixed; top: 20px; bottom: 20px; left: 20px; right: 20px; z-index: -1; background: #fff; box-shadow: 0 0 5px rgba(0, 0, 0, .3); overflow: auto; }
.overlay .spacer { background: linear-gradient(#88f, #0ff); }
.overlay-shown { z-index: 1; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<h1>Top of page</h1>
<p>Click to toggle overlay. (This is only scrollable when overlay is <em>not</em> open.)</p>
<div class="spacer"></div>
<h1>Bottom of page</h1>
<div id="overlay" class="overlay">
  <h1>Top of overlay</h1>
  <p>Click to toggle overlay. (Containing page is no longer scrollable, but this is.)</p>
  <div class="spacer"></div>
  <h1>Bottom of overlay</h1>
</div>

0b10011
źródło
Rzeczywiście działa, ale skaża projekt w przypadku stałego nagłówka, gdy pasek przewijania nurkuje pod nim.
Leon Willens
@LeonWillens Nie jestem pewien, co masz na myśli. Jeśli jesteś zaniepokojony nakładki występującego pod stałym nagłówka, musisz dostosować z-indexwśród .overlay-shownbyć większa niż ustalone cel. (Mam ten kod działający w trakcie produkcji na stronie ze stałym nagłówkiem i działa dobrze.)
0b10011
Nie, mówiłem o pasku przewijania bodyznacznika. Wczoraj eksperymentowałem z twoim kodem i mam stały nagłówek na górze mojej strony. Jeśli obsłużę przewijanie za pomocą bodyznacznika, pasek przewijania będzie pod stałym nagłówkiem.
Leon Willens,
1
@LeonWillens Ups, wygląda na to, że w pewnym momencie naprawiłem to i zapomniałem go zaktualizować. Wygląda na to, że zamiast tego $("body")używamy $(window). I zamiast z-index: -1nakładki, aby ją ukryć, możesz użyć visibility: hiddenlub podobnej. Zobacz jsfiddle.net/8p2gfeha, aby szybko sprawdzić, czy działa. Naprawiony nagłówek nie pojawia się już na pasku przewijania. W końcu postaram się włączyć te zmiany do odpowiedzi.
0b10011
Działa jak marzenie! Dziękuję :)
Leon Willens
1

Miałem podobny problem: menu po lewej stronie, które, gdy się pojawi, zapobiega przewijaniu. Gdy tylko wysokość została ustawiona na 100vh, pasek przewijania zniknął, a zawartość szarpnęła w prawo.

Jeśli więc nie przeszkadza ci pozostawienie włączonego paska przewijania (ale ustawienie okna na pełną wysokość, aby nigdzie się nie przewijało), inną możliwością jest ustawienie małego dolnego marginesu, który będzie wyświetlał paski przewijania:

body {
    height: 100vh;
    overflow: hidden;
    margin: 0 0 1px;
}
dhc
źródło
Czy to nie overflow:hiddenzapobiega wpływowi marginesu?
Koja
0

możesz zachować przepełnienie: ukryty, ale ręcznie zarządzać pozycją przewijania:

przed pokazaniem zachowaj ślad aktualnej pozycji przewijania:

var scroll = [$(document).scrollTop(),$(document).scrollLeft()];
//show your lightbox and then reapply scroll position
$(document).scrollTop(scroll[0]).scrollLeft(scroll[1]);

powinno działać

malko
źródło
0

Surowym, ale działającym sposobem będzie wymuszenie przewijania z powrotem na górę, a tym samym skuteczne wyłączenie przewijania:

var _stopScroll = false;
window.onload = function(event) {
    document.onscroll = function(ev) {
        if (_stopScroll) {
            document.body.scrollTop = "0px";
        }
    }
};

Po otwarciu lightbox podnieś flagę, a podczas zamykania opuść flagę.

Przypadek testowy na żywo .

Shadow Wizard is Ear For You
źródło
0

Lubię trzymać się metody „przepełnienie: ukryty” i po prostu dodać dopełnienie, które jest równe szerokości paska przewijania.

Uzyskaj funkcję szerokości paska przewijania, LostSource .

function getScrollbarWidth() {
    var outer = document.createElement("div");
    outer.style.visibility = "hidden";
    outer.style.width = "100px";
    outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps

    document.body.appendChild(outer);

    var widthNoScroll = outer.offsetWidth;
    // force scrollbars
    outer.style.overflow = "scroll";

    // add innerdiv
    var inner = document.createElement("div");
    inner.style.width = "100%";
    outer.appendChild(inner);        

    var widthWithScroll = inner.offsetWidth;

    // remove divs
    outer.parentNode.removeChild(outer);

    return widthNoScroll - widthWithScroll;
}

Podczas wyświetlania nakładki dodaj klasę „noscroll” do html i dodaj padding-right do body:

$(html).addClass("noscroll");
$(body).css("paddingRight", getScrollbarWidth() + "px");

Podczas ukrywania usuń klasę i dopełnienie:

$(html).removeClass("noscroll");
$(body).css("paddingRight", 0);

Styl noscroll jest taki:

.noscroll { overflow: hidden; }

Zauważ, że jeśli masz jakieś elementy z pozycją: naprawiono, musisz również dodać dopełnienie do tych elementów.

Janne Annala
źródło
Użyłem tego rozwiązania. Pomogło mi to uniknąć podwójnych pasków przewijania (jednego „pustego” dla ciała i drugiego dla zawartości nakładki). Działa również bardzo dobrze w systemie OSX, który może, ale nie musi, pokazywać pasków przewijania.
Novazembla,
0

<div id="lightbox">znajduje się w <body>elemencie, więc przewijając lightbox, przewijasz również ciało. Rozwiązaniem jest nie przedłużanie <body>elementu o ponad 100%, umieszczenie długiej zawartości wewnątrz innego divelementu i dodanie paska przewijania, jeśli to konieczne, do tego divelementu za pomocą overflow: auto.

html {
  height: 100%
}
body {
  margin: 0;
  height: 100%
}
#content {
  height: 100%;
  overflow: auto;
}
#lightbox {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
<html>
  <body>
    <div id="content">much content</div>
    <div id="lightbox">lightbox<div>
  </body>
</html>

Teraz przewijanie lightbox (i bodyrównież) nie ma żadnego efektu, ponieważ ciało nie jest dłuższe niż 100% wysokości ekranu.

Marek C.
źródło
0

Wszystkie systemy oparte na javascript modal / lightbox używają przepełnienia podczas wyświetlania modal / lightbox, na tagu HTML lub tagu body.

Gdy lightbox jest pokazany, js wypycha przepełnienie ukryte na html lub tagu body. Gdy lightbox jest ukryty, niektóre usuwają ukryte, inne wypychają automatyczne przelewanie na HTML lub tagu treści.

Programiści pracujący na komputerach Mac nie widzą problemu z paskiem przewijania.

Wystarczy zastąpić ukryty przez rozbrojenie, aby zawartość nie ślizgała się pod modą usunięcia paska przewijania.

Lightbox otwarty / pokaż:

<html style="overflow: unset;"></html>

Lightbox zamknij / ukryj:

<html style="overflow: auto;"></html>
Daszek u czapki
źródło
0

Jeśli stronę pod nakładką można „naprawić” u góry, po otwarciu nakładki można ustawić

.disableScroll { position: fixed; overflow-y:scroll }

podaj tę klasę do przewijalnego ciała, powinieneś nadal widzieć prawy pasek przewijania, ale zawartość nie jest przewijana.

Aby zachować pozycję strony, zrób to w jquery

$('body').css('top', - ($(window).scrollTop()) + 'px').addClass('disableScroll');

Po zamknięciu nakładki po prostu przywróć te właściwości za pomocą

var top = $('body').position().top;
$('body').removeClass('disableScroll').css('top', 0).scrollTop(Math.abs(top));

Właśnie zaproponowałem ten sposób tylko dlatego, że nie trzeba zmieniać żadnego zdarzenia przewijania

Bhuvan Arora
źródło
0

Spowoduje to, że rzutnia nie przejdzie do góry, zapisując pozycję przewijania i przywracając ją po włączeniu przewijania.

CSS

.no-scroll{
  position: fixed; 
  width:100%;
  min-height:100vh;
  top:0;
  left:0;
  overflow-y:scroll!important;
}

JS

var scrollTopPostion = 0;

function scroll_pause(){
  scrollTopPostion = $(window).scrollTop();
  $("body").addClass("no-scroll").css({"top":-1*scrollTopPostion+"px"});
}

function scroll_resume(){
  $("body").removeClass("no-scroll").removeAttr("style");
  $(window).scrollTop(scrollTopPostion);
}

Teraz wystarczy wywołać funkcje

$(document).on("click","#DISABLEelementID",function(){
   scroll_pause();
});

$(document).on("click","#ENABLEelementID",function(){
   scroll_resume();
});
Kareem
źródło
-1

Możesz to zrobić za pomocą Javascript:

// Classic JS
window.onscroll = function(ev) {
  ev.preventDefault();
}

// jQuery
$(window).scroll(function(ev) {
  ev.preventDefault();
}

A następnie wyłącz go, gdy twój lightbox jest zamknięty.

Ale jeśli Twój lightbox zawiera pasek przewijania, nie będziesz mógł przewijać, gdy jest otwarty. To dlatego, że windowzawiera zarówno bodyi #lightbox. Musisz więc użyć architektury takiej jak ta:

<body>
  <div id="global"></div>
  <div id="lightbox"></div>
</body>

A następnie zastosuj onscrollwydarzenie tylko w dniu #global.

ldiqual
źródło