Basta disabilitare lo scroll non nasconderlo?


198

Sto cercando di disabilitare la barra di scorrimento html / body del genitore mentre sto usando una lightbox. La parola principale qui è disabilita . Io non voglio nasconderlo con overflow: hidden;.

La ragione di ciò è che overflow: hiddenfa saltare il sito e occupare l'area in cui era lo scorrimento.

Voglio sapere se è possibile disabilitare una barra di scorrimento mentre la mostra ancora.


1
Dovrebbe essere possibile lo scorrimento? (La lightbox ha delle barre di scorrimento?)
Šime Vidas

il sito ha iniziato a scorrere ma voglio solo disabilitarlo mentre la lightbox è aperta. voglio solo sapere se è possibile disabilitare una barra di scorrimento mentre la mostra. non è necessario nient'altro come farlo in una lightbox o altro.
Dejan.S

qual è il problema utilizzando la lightbox con barra di scorrimento?
manny

1
@Dejan Perché so come disabilitare tutto lo scorrimento - questo disabiliterebbe la barra di scorrimento principale, ma anche quella nella lightbox ...
Šime Vidas

1
Ti preghiamo di non modificare la risposta in questo post. La sezione di risposta di seguito è per le risposte. Se hai una risposta alla tua domanda diversa da una di seguito, puoi aggiungere la tua soluzione nella selezione della risposta.
creatore

Risposte:


173

Se la pagina sotto l'overlay può essere "riparata" in alto, quando si apre l'overlay è possibile impostare

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

dovresti comunque vedere la barra di scorrimento destra ma il contenuto non è scorrevole. Quando chiudi l'overlay, ripristina queste proprietà con

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

Ho appena proposto in questo modo solo perché non sarebbe necessario modificare alcun evento di scorrimento

Aggiornare

Potresti anche fare un leggero miglioramento: se ottieni la document.documentElement.scrollTopproprietà via javascript appena prima dell'apertura del livello, puoi assegnare dinamicamente quel valore come topproprietà dell'elemento body: con questo approccio la pagina rimarrà al suo posto, non importa se tu ' in alto o se hai già fatto scorrere.

Css

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

JS

$('body').css('top', -(document.documentElement.scrollTop) + 'px')
         .addClass('noscroll');

2
rovina il mio layout ma con alcune modifiche potrebbe funzionare. mi piace, lo proverò di più
Dejan.S,

4
con una piccola modifica questo funziona. ho aggiunto una larghezza: 100%; sono andato aggiorna la mia domanda con la soluzione ma puoi modificarla con la larghezza: 100% ;? grazie per il suggerimento
Dejan.S

3
Non so perché, ma questo funziona meglio per me: $('body').css('top', -($('body').scrollTop()) + 'px').addClass('noscroll');
PDXIII

4
@whitesiroi, hai ragione. Ho aggiornato il violino: jsfiddle.net/evpozdniakov/2m8km9wg Grazie!
evpozdniakov,

1
Per coloro che leggono i commenti per una soluzione, l'ultimo violino fornisce una soluzione per disabilitare e riattivare la barra di scorrimento mantenendo la posizione della barra di scorrimento in entrambi i casi. Grazie!
user1063287

78

Quattro piccole aggiunte alla soluzione selezionata:

  1. Applica 'noscroll' a html anziché a body per evitare doppie barre di scorrimento in IE
  2. Per verificare se esiste effettivamente una barra di scorrimento prima di aggiungere la classe 'noscroll'. Altrimenti, il sito salterà anche spinto dalla nuova barra di scorrimento non scorrevole.
  3. Per mantenere ogni possibile scrollTop in modo che l'intera pagina non torni all'inizio (come l'aggiornamento di Fabrizio, ma è necessario afferrare il valore prima di aggiungere la classe 'noscroll')
  4. Non tutti i browser gestiscono scrollTop nello stesso modo documentato su http://help.dottoro.com/ljnvjiow.php

Soluzione completa che sembra funzionare per la maggior parte dei browser:

CSS

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

Disabilita lo scorrimento

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

Abilita scorrimento

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

Grazie a Fabrizio e Dejan per avermi messo sulla buona strada e a Brodingo per la soluzione alla doppia barra di scorrimento


1
Questo è stato testato bene sul desktop ma su iPhone ha creato uno schermo bianco vuoto fino a quando il lettore ha tentato di scorrere la pagina. Una volta che il lettore ha provato a interagire con la pagina, la schermata desiderata è diventata visibile con lo scorrimento bloccato.
Michael Khalili,

Questo ha funzionato perfettamente con Fancybox su iPad per disabilitare lo scorrimento dell'immagine lightbox con afterLoad()e afterCloserichiamate. Potrebbe essere utile per gli altri che cercano questa domanda.
Tomanow,

Nella parte "abilita scorrimento", potresti voler rimuovere l'attributo di stile che viene posizionato sull'elemento html dopo una chiamata a "disabilitare lo scorrimento"; no?
Ben

3
jQuery standardizza i DOM nativi in ​​modo scrollToptale che la riga 2 del codice "Disable scroll" possa essere espressa come $( window ).scrollTop().
Barney,

Penso che un'altra cosa debba essere aggiunta a questo. Su Chrome in OSX, è possibile che il browser "esegua l'over-scroll", dando allo scorrimento una sensazione elastica. Con questo codice se ti trovi nell'area grigia sopra o sotto la pagina e passi con il mouse sopra un punto in cui disabiliti lo scorrimento. Si attaccherà in un punto sopra / sotto la finestra del browser. Per questo motivo è necessario aggiungere un controllo per un valore di scorrimento negativo: if (scrollTop < 0) { scrollTop = 0; }. Ecco il codice completo per disabilitare gist.github.com/jayd3e/2eefbbc571cd1668544b .
JayD3e,

34

Con jQuery incluso:


disattivare

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

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

abilitare

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

uso

//disable
$("#selector").disableScroll();
//enable
$("#selector").enableScroll();

1
questo è stato perfetto per me, la risposta precedente ha fatto rimbalzare la mia pagina, questa no
Bogdan Tomi,

felice di poterti aiutare, potresti aver bisogno di controllare anche "touchmove", per dispositivi mobili, evviva
ceed

Bene, questo ha quasi funzionato per me. Ha funzionato a meraviglia su Windows (Firefox, Chrome) e MacOS in Firefox ... ma poi sono andato a Windows IE e Edge, insieme a MacOS in Chrome e Safari. Il problema non riguardava più la pagina che saltava da una parte all'altra, ma la barra di scorrimento stava saltando dall'alto verso la posizione corrente o la pagina tremolava in alto. Amico, era così , così vicino. Forse possiamo ancora farlo funzionare.
Steven Ventimiglia,

Questo ha funzionato perfettamente per me, grazie! Ideale per l'uso su un sito Web in cui il menu di sovrapposizione è anche nella parte inferiore della pagina!
SauriolJf

12

Sono l'OP

Con l'aiuto della risposta di fcalderan sono stato in grado di formare una soluzione. Lascio qui la mia soluzione perché chiarisce come usarla e aggiunge un dettaglio molto cruciale,width: 100%;

Aggiungo questa classe

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

questo ha funzionato per me e stavo usando Fancyapp.


11

Questo ha funzionato davvero bene per me ....

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

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


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

basta avvolgere quelle due righe di codice con qualunque cosa decida quando si intende bloccare lo scorrimento.

per esempio

$('button').on('click', function() {
     $('body').bind('mousewheel touchmove', lockScroll);
});

Questa è la migliore risposta a tutte
Jafo

7

Non è possibile disabilitare l'evento scroll, ma è possibile disabilitare le azioni correlate che portano a uno scroll, come rotellina del mouse e touchmove:

$('body').on('mousewheel touchmove', function(e) {
      e.preventDefault();
});

4

Puoi nascondere la barra di scorrimento del corpo con overflow: hiddene impostare un margine allo stesso tempo in modo che il contenuto non salti:

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

Quindi puoi aggiungere una barra di scorrimento disabilitata alla pagina per riempire il vuoto:

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>

Ho fatto esattamente questo per la mia implementazione di lightbox. Sembra funzionare bene finora.


1
In realtà mi piace questo metodo il migliore. Molto semplice e funziona alla grande. Grazie!
Dericcain,

2

Questa è la soluzione con cui siamo andati. Basta salvare la posizione di scorrimento quando viene aperto l'overlay, scorrere indietro fino alla posizione salvata ogni volta che l'utente ha tentato di scorrere la pagina e disattivare l'ascoltatore quando l'overlay è chiuso.

È un po 'nervoso su IE, ma funziona come un incantesimo su 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>


Funziona davvero, ma altera il design nel caso di un'intestazione fissa, mentre la barra di scorrimento si tuffa sotto di essa.
Leon Willens,

@LeonWillens Non sono sicuro di cosa intendi. Se sei preoccupato che l'overlay appaia sotto un'intestazione fissa, dovrai regolare z-indexdi .overlay-shownper essere maggiore dell'intestazione fissa. (Ho questo codice in esecuzione in produzione su un sito con un'intestazione fissa e funziona benissimo.)
0b10011

No, stavo parlando della barra di scorrimento del bodytag. Ho sperimentato il tuo codice ieri e ho un'intestazione fissa nella parte superiore della mia pagina. Se gestisco lo scorrimento tramite il bodytag, la barra di scorrimento sarà sotto l'intestazione fissa.
Leon Willens,

1
@LeonWillens Oops, sembra che abbia risolto questo problema in produzione ad un certo punto e ho dimenticato di aggiornarlo. Sembra invece che $("body"), stiamo usando $(window). E invece che z-index: -1sull'overlay per nasconderlo, puoi usare visibility: hiddeno simili. Vedi jsfiddle.net/8p2gfeha per un rapido test per vedere se funziona. L'intestazione fissa non viene più visualizzata nella parte superiore della barra di scorrimento. Cercherò infine di incorporare questi cambiamenti nella risposta.
0b10011

Funziona come un fascino! Grazie :)
Leon Willens,

1

Ho avuto un problema simile: un menu a sinistra che, quando appare, impedisce lo scorrimento. Non appena l'altezza è stata impostata su 100 Vh, la barra di scorrimento è scomparsa e il contenuto è scattato a destra.

Quindi, se non ti dispiace mantenere abilitata la barra di scorrimento (ma impostando la finestra a tutta altezza in modo che non scorra effettivamente da nessuna parte), un'altra possibilità è impostare un piccolo margine inferiore, che manterrà le barre di scorrimento che mostrano:

body {
    height: 100vh;
    overflow: hidden;
    margin: 0 0 1px;
}

Ciò overflow:hiddenimpedisce al margine di avere alcun effetto?
Koja

0

puoi mantenere l'overflow: nascosto ma gestisci manualmente la posizione di scorrimento:

prima di mostrare tenere traccia della posizione di scorrimento effettiva:

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

dovrebbe funzionare


0

Il modo grezzo ma efficace sarà forzare lo scorrimento verso l'alto, disabilitando così in modo efficace lo scorrimento:

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

Quando apri la lightbox alza la bandiera e quando la chiudi, abbassa la bandiera.

Caso di prova dal vivo .


0

Mi piace attenermi al metodo "overflow: hidden" e aggiungere solo il padding-right che è uguale alla larghezza della barra di scorrimento.

Ottieni la funzione di larghezza della barra di scorrimento, da 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;
}

Quando mostri l'overlay, aggiungi la classe "noscroll" a html e aggiungi padding-right to body:

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

Quando ti nascondi, rimuovi la classe e il riempimento:

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

Lo stile noscroll è proprio questo:

.noscroll { overflow: hidden; }

Nota che se hai elementi con posizione: riparato devi aggiungere anche l'imbottitura a quegli elementi.


Ho usato questa soluzione. Mi ha aiutato a evitare le doppie barre di scorrimento (una "vuota" per il corpo e una seconda per il contenuto della sovrapposizione). Funziona anche molto bene su OSX che potrebbe o meno mostrare le barre di scorrimento.
Novazembla,

0

<div id="lightbox">si trova all'interno <body>dell'elemento, quindi quando si scorre la lightbox si scorre anche il corpo. La soluzione è non estendere l' <body>elemento oltre il 100%, posizionare il contenuto lungo all'interno di un altro divelemento e aggiungere una barra di scorrimento se necessario a questo divelemento con 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>

Ora, scorrere sopra la lightbox (e bodyanche) non ha alcun effetto, perché il corpo non supera il 100% dell'altezza dello schermo.


0

Tutti i sistemi basati su javascript modale / lightbox utilizzano un overflow quando si visualizza il modale / lightbox, su tag html o tag body.

Quando viene mostrato lightbox, js invia un overflow nascosto su html o tag body. Quando la lightbox è nascosta, alcuni rimuovono l'altro push spingendo un'auto overflow su html o tag body.

Gli sviluppatori che lavorano su Mac non vedono il problema della barra di scorrimento.

Sostituisci semplicemente il nascosto con un unset per non vedere il contenuto scivolare sotto la modalità di rimozione della barra di scorrimento.

Lightbox aperto / mostra:

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

Lightbox chiudere / nascondere:

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

0

Se la pagina sotto l'overlay può essere "riparata" in alto, quando si apre l'overlay è possibile impostare

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

fornire questa classe al corpo scorrevole, dovresti comunque vedere la barra di scorrimento corretta ma il contenuto non è scorrevole.

Per mantenere la posizione della pagina, eseguire questa operazione in jquery

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

Quando chiudi l'overlay, ripristina queste proprietà con

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

Ho appena proposto in questo modo solo perché non sarebbe necessario modificare alcun evento di scorrimento


0

Ciò impedirà al viewport di saltare in alto salvando la posizione di scorrimento e ripristinandola abilitando lo scorrimento.

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

Ora tutto ciò che devi fare è chiamare le funzioni

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

$(document).on("click","#ENABLEelementID",function(){
   scroll_resume();
});

-1

Puoi farlo con Javascript:

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

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

E poi disabilitalo quando la lightbox è chiusa.

Ma se il tuo lightbox contiene una barra di scorrimento, non sarai in grado di scorrere mentre è aperto. Questo perché windowcontiene sia bodye #lightbox. Quindi devi usare un'architettura come la seguente:

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

E quindi applicare l' onscrollevento solo su #global.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.