¿Solo deshabilitar el desplazamiento, no ocultarlo?

198

Estoy tratando de deshabilitar la barra de desplazamiento html / body del padre mientras estoy usando una caja de luz. La palabra principal aquí es deshabilitar . Yo no quiero ocultarlo con overflow: hidden;.

La razón de esto es que overflow: hiddenhace que el sitio salte y ocupe el área donde estaba el pergamino.

Quiero saber si es posible desactivar una barra de desplazamiento mientras la sigo mostrando.

Dejan.S
fuente
1
¿Debería ser posible algún desplazamiento? (¿La caja de luz tiene barras de desplazamiento?)
Šime Vidas
el sitio se desplazó pero solo quiero deshabilitarlo mientras la caja de luz está abierta. Solo quiero saber si es posible desactivar una barra de desplazamiento mientras se muestra. No se necesita nada más, como hacerlo en una caja de luz o cualquier otra cosa.
Dejan.S
¿Cuál es el problema al usar lightbox con barra de desplazamiento?
manny
1
@Dejan Porque sé cómo deshabilitar todo el desplazamiento, eso deshabilitaría la barra de desplazamiento principal, pero también la que está en la caja de luz ...
Šime Vidas
1
Por favor, no edite la respuesta en esta publicación. La sección de respuestas a continuación es para respuestas. Si tiene una respuesta a su pregunta que es diferente de la respuesta a continuación, puede agregar su propia solución en la selección de respuestas.
intcreator

Respuestas:

173

Si la página debajo de la capa superpuesta se puede "arreglar" en la parte superior, cuando abre la capa superpuesta puede configurar

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

aún debería ver la barra de desplazamiento derecha pero el contenido no se puede desplazar. Cuando cierre la superposición, simplemente revierta estas propiedades con

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

Solo propuse de esta manera solo porque no necesitarías cambiar ningún evento de desplazamiento

Actualizar

También podría hacer una pequeña mejora: si obtiene la document.documentElement.scrollToppropiedad a través de JavaScript justo antes de que se abra la capa, puede asignar dinámicamente ese valor como toppropiedad del elemento del cuerpo: con este enfoque, la página se mantendrá en su lugar, sin importar si usted ' volver arriba o si ya te has desplazado.

Css

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

JS

$('body').css('top', -(document.documentElement.scrollTop) + 'px')
         .addClass('noscroll');
Fabrizio Calderan
fuente
2
se mete con mi diseño, pero con algunas modificaciones podría funcionar. me gusta, lo probaré más
Dejan.S
44
con una pequeña modificación esto funciona. agregué un ancho: 100%; He ido a actualizar mi pregunta con la solución, pero puede modificar su con el ancho: 100% ;? gracias por la sugerencia
Dejan.S
3
No sé por qué, pero esto funciona mejor para mí: $('body').css('top', -($('body').scrollTop()) + 'px').addClass('noscroll');
PDXIII
44
@whitesiroi, tienes razón. He actualizado el violín: jsfiddle.net/evpozdniakov/2m8km9wg ¡ Gracias!
evpozdniakov
1
Para aquellos que leen los comentarios para una solución, el último violín proporciona una solución para deshabilitar y volver a habilitar la barra de desplazamiento mientras se mantiene la posición de la barra de desplazamiento en ambos casos. ¡Gracias!
user1063287
78

Cuatro pequeñas adiciones a la solución seleccionada:

  1. Aplicar 'noscroll' a html en lugar de al cuerpo para evitar barras de desplazamiento dobles en IE
  2. Para verificar si realmente hay una barra de desplazamiento antes de agregar la clase 'noscroll'. De lo contrario, el sitio también saltará impulsado por la nueva barra de desplazamiento sin desplazamiento.
  3. Para mantener cualquier posible scrollTop para que toda la página no vuelva al principio (como la actualización de Fabrizio, pero debe tomar el valor antes de agregar la clase 'noscroll')
  4. No todos los navegadores manejan scrollTop de la misma manera que se documenta en http://help.dottoro.com/ljnvjiow.php

Solución completa que parece funcionar para la mayoría de los navegadores:

CSS

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

Deshabilitar desplazamiento

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

Habilitar desplazamiento

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

Gracias a Fabrizio y Dejan por ponerme en el camino correcto y a Brodingo por la solución a la barra de desplazamiento doble.

Mike García
fuente
1
Esto probó bien en el escritorio, pero en el iPhone creó una pantalla blanca en blanco hasta que el lector intentó desplazarse por la página. Una vez que el lector intentó interactuar con la página, la pantalla deseada se hizo visible con el desplazamiento bloqueado.
Michael Khalili
Esto funcionó perfectamente con FancyBox en el iPad para desactivar el desplazamiento de la imagen caja de luz con afterLoad()y afterClosedevoluciones de llamada. Podría ser útil para otros que buscan esta pregunta.
Tomanow
En la parte "habilitar desplazamiento", es posible que desee eliminar el atributo de estilo que se coloca en el elemento html después de una llamada para "desactivar desplazamiento"; no tu
Ben
3
jQuery estandariza los DOM nativos de scrollToptal manera que la línea 2 del código 'Deshabilitar desplazamiento' se puede expresar como $( window ).scrollTop().
Barney
Creo que hay que agregar otra cosa a esto. En Chrome en OSX, es posible que el navegador "se desplace en exceso", dando al desplazamiento una sensación elástica. Con este código, si está en el área gris encima o debajo de la página y pasa el cursor sobre un punto donde deshabilita el desplazamiento. Se mantendrá en un lugar arriba / debajo de la ventana del navegador. Por esta razón es necesario agregar un cheque por un valor de desplazamiento negativo: if (scrollTop < 0) { scrollTop = 0; }. Aquí está el código completo para deshabilitar gist.github.com/jayd3e/2eefbbc571cd1668544b .
JayD3e
34

Con jQuery incluido:


inhabilitar

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

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

habilitar

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

uso

//disable
$("#selector").disableScroll();
//enable
$("#selector").enableScroll();
ceed
fuente
1
esto fue perfecto para mí, la respuesta anterior hizo que mi página rebotara, esta no lo hace
Bogdan Tomi
Me alegro de poder ayudar, puede que tenga que comprobar si hay "touchmove" también, para los dispositivos móviles, vivas
CEED
Bueno, esto casi funcionó para mí. Funcionó de maravilla en Windows (Firefox, Chrome) y MacOS en Firefox ... pero luego fui a Windows IE y Edge, junto con MacOS en Chrome y Safari. El problema ya no era que la página saltara de lado a lado, sino que la barra de desplazamiento saltaba de arriba a la posición actual o la página parpadeaba hacia arriba. Hombre, esto estaba muy , muy cerca. Quizás aún podamos hacerlo funcionar.
Steven Ventimiglia
Esto funcionó perfectamente para mí, ¡gracias! ¡Ideal para usar en un sitio web donde el menú de superposición también se encuentra al final de la página!
SauriolJf
12

Soy el OP

Con la ayuda de la respuesta de fcalderan pude formar una solución. Dejo mi solución aquí, ya que aporta claridad sobre cómo usarla y agrega un detalle crucial,width: 100%;

Agrego esta clase

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

esto funcionó para mí y estaba usando Fancyapp.

Dejan.S
fuente
11

Esto funcionó muy bien para mí ...

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

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


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

simplemente envuelva esas dos líneas de código con lo que decida cuándo va a bloquear el desplazamiento.

p.ej

$('button').on('click', function() {
     $('body').bind('mousewheel touchmove', lockScroll);
});
dmackenz
fuente
Esta es la mejor respuesta de todas
Jafo
7

No puede deshabilitar el evento de desplazamiento, pero puede deshabilitar las acciones relacionadas que conducen a un desplazamiento, como la rueda del mouse y la tecla táctil:

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

Puede ocultar la barra de desplazamiento del cuerpo overflow: hiddeny establecer un margen al mismo tiempo para que el contenido no salte:

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

Y luego puede agregar una barra de desplazamiento deshabilitada a la página para llenar el vacío:

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>

Hice exactamente esto para mi propia implementación de lightbox. Parece estar funcionando bien hasta ahora.

mpen
fuente
1
De hecho, me gusta este método lo mejor. Muy simple y funciona muy bien. ¡Gracias!
dericcain
2

Esta es la solución con la que fuimos. Simplemente guarde la posición de desplazamiento cuando se abra la superposición, vuelva a la posición guardada cada vez que el usuario intente desplazarse por la página y apague el oyente cuando la superposición esté cerrada.

Es un poco nervioso en IE, pero funciona de maravilla en 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
fuente
Funciona de hecho, pero contamina el diseño en caso de un encabezado fijo, ya que la barra de desplazamiento se sumerge debajo de él.
Leon Willens
@LeonWillens No estoy seguro de lo que quieres decir. Si le preocupa que la superposición aparezca debajo de un encabezado fijo, deberá ajustar la z-indexde .overlay-shownpara que sea mayor que el encabezado fijo. (Tengo este código ejecutándose en producción en un sitio con un encabezado fijo y funciona bien).
0b10011
No, estaba hablando de la barra de desplazamiento de la bodyetiqueta. Experimenté con su código ayer y tengo un encabezado fijo en la parte superior de mi página. Si manejo el desplazamiento a través de la bodyetiqueta, la barra de desplazamiento estará debajo del encabezado fijo.
Leon Willens
1
@LeonWillens Vaya, parece que arreglé esto en producción en algún momento y olvidé actualizarlo. Parece que en lugar de $("body"), estamos usando $(window). Y en lugar de z-index: -1en la superposición para ocultarlo, puede usar visibility: hiddeno similar. Vea jsfiddle.net/8p2gfeha para una prueba rápida para ver si funciona. El encabezado fijo ya no aparece en la parte superior de la barra de desplazamiento. Eventualmente intentaré incorporar estos cambios en la respuesta.
0b10011
¡Funciona de maravilla! Gracias :)
Leon Willens
1

Tuve un problema similar: un menú de la izquierda que, cuando aparece, impide el desplazamiento. Tan pronto como la altura se estableció en 100vh, la barra de desplazamiento desapareció y el contenido se movió hacia la derecha.

Entonces, si no le importa mantener la barra de desplazamiento habilitada (pero configurando la ventana a la altura completa para que no se desplace en ninguna parte), otra posibilidad es establecer un pequeño margen inferior, que mantendrá las barras de desplazamiento mostrando:

body {
    height: 100vh;
    overflow: hidden;
    margin: 0 0 1px;
}
dhc
fuente
¿No overflow:hiddenimpide que el margen tenga efecto?
Koja
0

puede mantener el desbordamiento: oculto pero administrar manualmente la posición de desplazamiento:

antes de mostrar el rastro de la posición de desplazamiento real:

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

deberia de funcionar

malko
fuente
0

Una forma cruda pero funcional será forzar el desplazamiento hacia arriba, desactivando así el desplazamiento:

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

Cuando abra la caja de luz, levante la bandera y, al cerrarla, baje la bandera.

Caso de prueba en vivo .

Shadow Wizard es Ear for You
fuente
0

Me gusta apegarme al método "desbordamiento: oculto" y simplemente agregar el relleno derecho que es igual al ancho de la barra de desplazamiento.

Obtener la función de ancho de la barra de desplazamiento, por 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;
}

Al mostrar la superposición, agregue la clase "noscroll" a html y agregue padding-right al cuerpo:

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

Al esconderse, elimine la clase y el relleno:

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

El estilo noscroll es solo esto:

.noscroll { overflow: hidden; }

Tenga en cuenta que si tiene elementos con posición: fijo, también debe agregar el relleno a esos elementos.

Janne Annala
fuente
Usé esta solución. Me ayudó a evitar las barras de desplazamiento dobles (una 'en blanco' para el cuerpo y una segunda para el contenido de la superposición). También funciona muy bien en OSX que puede mostrar o no barras de desplazamiento.
Novazembla
0

<div id="lightbox">está dentro del <body>elemento, por lo tanto, cuando desplaza la caja de luz, también desplaza el cuerpo. La solución es no extender el <body>elemento más del 100%, colocar el contenido largo dentro de otro divelemento y agregar una barra de desplazamiento si es necesario con este divelemento 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>

Ahora, desplazarse sobre la caja de luz (y bodytambién) no tiene ningún efecto, porque el cuerpo no tiene más del 100% de la altura de la pantalla.

Marek C
fuente
0

Todos los sistemas basados ​​en JavaScript modal / lightbox utilizan un desbordamiento cuando se muestran modal / lightbox, en la etiqueta html o etiqueta corporal.

Cuando se muestra lightbox, el js empuja un desbordamiento oculto en html o etiqueta de cuerpo. Cuando lightbox está oculto, algunos eliminan el oculto, otros empujan un desbordamiento automático en html o etiqueta de cuerpo.

Los desarrolladores que trabajan en Mac no ven el problema de la barra de desplazamiento.

Simplemente reemplace lo oculto por un desarmado para no ver el contenido deslizarse bajo el modal de la eliminación de la barra de desplazamiento.

Caja de luz abierta / mostrar:

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

Lightbox cerrar / ocultar:

<html style="overflow: auto;"></html>
Visera
fuente
0

Si la página debajo de la capa superpuesta se puede "arreglar" en la parte superior, cuando abre la capa superpuesta puede configurar

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

proporcione esta clase al cuerpo desplazable, aún debería ver la barra de desplazamiento derecha pero el contenido no se puede desplazar.

Para mantener la posición de la página, haga esto en jquery

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

Cuando cierre la superposición, simplemente revierta estas propiedades con

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

Solo propuse de esta manera solo porque no necesitarías cambiar ningún evento de desplazamiento

Bhuvan Arora
fuente
0

Esto evitará que la ventana salte a la parte superior al guardar la posición de desplazamiento y restaurarla para habilitar el desplazamiento.

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

Ahora todo lo que necesitas hacer es llamar a las funciones

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

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

Puedes hacerlo con Javascript:

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

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

Y luego deshabilítelo cuando su caja de luz esté cerrada.

Pero si su caja de luz contiene una barra de desplazamiento, no podrá desplazarse mientras esté abierta. Esto es porque windowcontiene ambos bodyy #lightbox. Entonces debe usar una arquitectura como la siguiente:

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

Y luego aplique el onscrollevento solo en #global.

ldiqual
fuente