Evite que BODY se desplace cuando se abre un modal


346

Quiero que mi cuerpo deje de desplazarse cuando use la rueda del mouse mientras esté abierto el Modal (de http://twitter.github.com/bootstrap ) en mi sitio web.

Intenté llamar a la pieza de JavaScript a continuación cuando se abre el modal pero sin éxito

$(window).scroll(function() { return false; });

Y

$(window).live('scroll', function() { return false; });

Tenga en cuenta que nuestro sitio web dejó de ser compatible con IE6, aunque IE7 + debe ser compatible.

Respuestas:


468

Bootstrap modalagrega automáticamente la clase modal-openal cuerpo cuando se muestra un cuadro de diálogo modal y lo elimina cuando el cuadro de diálogo está oculto. Por lo tanto, puede agregar lo siguiente a su CSS:

body.modal-open {
    overflow: hidden;
}

Podría argumentar que el código anterior pertenece a la base de código CSS Bootstrap, pero esta es una solución fácil para agregarlo a su sitio.

Actualización 8 de febrero de 2013
Esto ha dejado de funcionar en Twitter Bootstrap v. 2.3.0: ya no agregan la modal-openclase al cuerpo.

Una solución alternativa sería agregar la clase al cuerpo cuando se va a mostrar el modal y eliminarlo cuando se cierre el modal:

$("#myModal").on("show", function () {
  $("body").addClass("modal-open");
}).on("hidden", function () {
  $("body").removeClass("modal-open")
});

Actualización 11 de marzo de 2013 Parece que la modal-openclase volverá en Bootstrap 3.0, explícitamente con el fin de evitar el desplazamiento:

Reintroduce .modal-open en el cuerpo (para que podamos desplazar el desplazamiento allí)

Vea esto: https://github.com/twitter/bootstrap/pull/6342 - mire la sección Modal .


2
esto ya no funciona en bootstrap 2.2.2. Esperemos que .modal-open vuelva en el futuro ... github.com/twitter/bootstrap/issues/5719
ppetrid

2
@ppetrid No espero que vuelva. En base a este escrito: github.com/twitter/bootstrap/wiki/Upcoming-3.0-changes (mira en la parte inferior). Cita: "No más desplazamiento modal interno. En cambio, los modales crecerán para albergar su contenido y el desplazamiento de la página para albergar el modal".
MartinHN

2
@Bagata Cool: modal-openvolverá en Bootstrap 3, por lo que cuando se inicie, debería ser seguro eliminar el código anterior.
MartinHN

2
Es por eso que uno debe seguir desplazándose hacia abajo, si la respuesta elegida no lo satisface, hay posibilidades de que encuentre gemas como estas. no esperaba una respuesta votada más de 97 enterrada tan profundamente bajo otros comentarios menos me gusta.
Mohd Abdul Mujib

2
El problema con esto es que para evitar que el documento se desplace hacia la parte superior cuando se abre un modal, debe agregar body.modal-open {overflow: visible}. Su solución funciona en este momento, con la desventaja de que será el desplazamiento a la parte superior una vez al modal se openen
Patrick

120

La respuesta aceptada no funciona en dispositivos móviles (iOS 7 con Safari 7, al menos) y no quiero que se ejecute MOAR JavaScript en mi sitio cuando CSS lo haga.

Este CSS evitará que la página de fondo se desplace bajo el modal:

body.modal-open {
    overflow: hidden;
    position: fixed;
}

Sin embargo, también tiene un ligero efecto secundario de desplazarse esencialmente hacia la parte superior. position:absoluteresuelve esto, pero reintroduce la capacidad de desplazarse en el móvil.

Si conoce su ventana gráfica ( mi complemento para agregar la ventana gráfica a<body> ) puede simplemente agregar una palanca css para position.

body.modal-open {
    // block scroll for mobile;
    // causes underlying page to jump to top;
    // prevents scrolling on all screens
    overflow: hidden;
    position: fixed;
}
body.viewport-lg {
    // block scroll for desktop;
    // will not jump to top;
    // will not prevent scroll on mobile
    position: absolute; 
}

También agrego esto para evitar que la página subyacente salte hacia la izquierda / derecha al mostrar / ocultar modales.

body {
    // STOP MOVING AROUND!
    overflow-x: hidden;
    overflow-y: scroll !important;
}

esta respuesta es una x-post.


77
¡Gracias! Los móviles (al menos el navegador nativo iOS y Android) me daban dolor de cabeza y no funcionarían sin position: fixedel cuerpo.
Raul Rene

Gracias por incluir también el código para evitar que la página salte hacia la izquierda / derecha al mostrar / ocultar modales. Esto fue extremadamente útil y verifiqué que soluciona un problema que tenía en Safari en un iPhone 5c con iOS 9.2.1.
Elijah Lofgren

66
Para fijar el desplazamiento hacia arriba, puede registrar la posición antes de agregar la clase, luego, después de eliminar la clase, haga window.scroll a la posición registrada. Así es como lo arreglé por mí mismo: pastebin.com/Vpsz07zd .
Herramienta del

Aunque siento que esto solo se ajusta a necesidades muy básicas, fue una solución útil. Gracias.
Steve Benner

33

Simplemente oculta el desbordamiento del cuerpo y hace que el cuerpo no se desplace. Cuando oculte el modal, revertirlo a automático.

Aquí está el código:

$('#adminModal').modal().on('shown', function(){
    $('body').css('overflow', 'hidden');
}).on('hidden', function(){
    $('body').css('overflow', 'auto');
})

¡Excelente! Esto me ayudó. Gracias.
pfcodes

21

Puede intentar establecer el tamaño del cuerpo en tamaño de ventana con desbordamiento: oculto cuando modal está abierto


12
hacerlo movería la pantalla cada vez que se abre el modal, eso no es conveniente, solo necesito deshabilitar el desplazamiento de fondo
xorinzor

no estoy seguro de que puedas desplazar las barras están relacionadas con el navegador y no puedes hacer mucho con ellas
charlietfl

podría establecer modal en "fijo" para que no se mueva al desplazarse
charlietfl

8
no se trata de detener el desplazamiento del modal, se trata de detener el desplazamiento del fondo en el fondo
xorinzor

1
es la ventana que se desplaza si el cuerpo lo desborda. Por ejemplo, las barras de desplazamiento no son parte del documento.
charlietfl

18

Debe ir más allá de la respuesta de @ charlietfl y tener en cuenta las barras de desplazamiento, de lo contrario, puede ver un reflujo de documentos.

Apertura del modal:

  1. Registrar el bodyancho
  2. Establecer bodydesbordamiento enhidden
  3. Establezca explícitamente el ancho del cuerpo a lo que era en el paso 1.

    var $body = $(document.body);
    var oldWidth = $body.innerWidth();
    $body.css("overflow", "hidden");
    $body.width(oldWidth);

Cerrando el modal:

  1. Establecer bodydesbordamiento enauto
  2. Establecer bodyancho aauto

    var $body = $(document.body);
    $body.css("overflow", "auto");
    $body.width("auto");

Inspirado por: http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php


Estaba recibiendo una pantalla "nerviosa" por falta de un término mejor y la clave aquí para mí era seguir la configuración de ancho. Gracias una tonelada.
Hcabnettek

1
@Hcabnettek Sí: "jumpy" == "reflujo de documentos". ¡Me alegra que te haya ayudado! :-)
jpap

¿Hay una solución CSS para esto? ¿Funciona en todos los navegadores y dispositivos móviles?
Ruben

solo un error tipográfico: debe estar $body.css("overflow", "auto");en el último paso :)
schneikai

Oh hombre, qué idea tan maravillosa. @jpap, me ayudaste a resolver el problema de reflujo de documentos que me estaba molestando durante mucho tiempo.
Goran Radulovic

17

Advertencia: la siguiente opción no es relevante para Bootstrap v3.0.x, ya que el desplazamiento en esas versiones se ha limitado explícitamente al modal en sí. Si deshabilita los eventos de rueda, puede evitar inadvertidamente que algunos usuarios vean el contenido en modales que tienen alturas superiores a la altura de la ventana gráfica.


Otra opción más: eventos de rueda

El evento de desplazamiento no es cancelable. Sin embargo, es posible cancelar los eventos de rueda del mouse y rueda . La gran advertencia es que no todos los navegadores heredados son compatibles, Mozilla solo recientemente agregó soporte para este último en Gecko 17.0. No conozco la extensión completa, pero IE6 + y Chrome sí los admiten.

Aquí se explica cómo aprovecharlos:

$('#myModal')
  .on('shown', function () {
    $('body').on('wheel.modal mousewheel.modal', function () {
      return false;
    });
  })
  .on('hidden', function () {
    $('body').off('wheel.modal mousewheel.modal');
  });

JSFiddle


Su JSFiddle no funciona en Firefox 24, Chrome 24 ni en IE9.
AxeEffect

@AxeEffect debería estar funcionando ahora. El único problema era que las referencias externas a la biblioteca Bootstrap habían cambiado. Gracias por el aviso.
merv

2
Esto no evita que los dispositivos táctiles se desplacen, overflow:hiddenes mejor por ahora.
Webinan

55
Todos funcionan pero no para dispositivos móviles. -__- Probado Android 4.1 y Chrome
Tower Jimmy

@TowerJimmy probablemente necesite cancelar los eventos táctiles o de arrastre para eso (si eso es posible)
xorinzor

9
/* =============================
 * Disable / Enable Page Scroll
 * when Bootstrap Modals are
 * shown / hidden
 * ============================= */

function preventDefault(e) {
  e = e || window.event;
  if (e.preventDefault)
      e.preventDefault();
  e.returnValue = false;  
}

function theMouseWheel(e) {
  preventDefault(e);
}

function disable_scroll() {
  if (window.addEventListener) {
      window.addEventListener('DOMMouseScroll', theMouseWheel, false);
  }
  window.onmousewheel = document.onmousewheel = theMouseWheel;
}

function enable_scroll() {
    if (window.removeEventListener) {
        window.removeEventListener('DOMMouseScroll', theMouseWheel, false);
    }
    window.onmousewheel = document.onmousewheel = null;  
}

$(function () {
  // disable page scrolling when modal is shown
  $(".modal").on('show', function () { disable_scroll(); });
  // enable page scrolling when modal is hidden
  $(".modal").on('hide', function () { enable_scroll(); });
});

9

No se pudo hacer que funcione en Chrome simplemente cambiando CSS, porque no quería que la página volviera a la parte superior. Esto funcionó bien:

$("#myModal").on("show.bs.modal", function () {
  var top = $("body").scrollTop(); $("body").css('position','fixed').css('overflow','hidden').css('top',-top).css('width','100%').css('height',top+5000);
}).on("hide.bs.modal", function () {
  var top = $("body").position().top; $("body").css('position','relative').css('overflow','auto').css('top',0).scrollTop(-top);
});

1
Esta es la única solución que funcionó para mí en Bootstrap 3.2.
volx757

1
Tuve el salto al problema superior con sidenavs de material angular. Esta fue la única respuesta que parece funcionar en todos los casos (escritorio / móvil + permitir desplazamiento en el modo / sidenav + dejar la posición de desplazamiento del cuerpo fija sin saltar).
cYrixmorten

Esta es también la única solución que realmente funcionó para mí. tx
Deedz

funcionó para mí, bootstrap v4
Deano

9

Prueba este:

.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
    height: 100%;
}

Funcionó para mí. (soporta IE8)


44
Esto funciona pero también hace que saltes a la cima cuando abres un modal cuando lo usas position: fixed.
AlexioVay

8

Para Bootstrap , puede probar esto (trabajando en Firefox, Chromey Microsoft Edge):

body.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
}

Espero que esto ayude...


7

Agregar la clase 'is-modal-open' o modificar el estilo de la etiqueta del cuerpo con javascript está bien y funcionará como se supone. Pero el problema al que nos enfrentaremos es cuando el cuerpo se desborde: oculto, saltará a la parte superior (scrollTop se convertirá en 0). Esto se convertirá en un problema de usabilidad más adelante.

Como solución para este problema, en lugar de cambiar el desbordamiento de la etiqueta del cuerpo: oculto cámbielo en la etiqueta html

$('#myModal').on('shown.bs.modal', function () {
  $('html').css('overflow','hidden');
}).on('hidden.bs.modal', function() {
  $('html').css('overflow','auto');
});

1
Esta es absolutamente la respuesta correcta porque la respuesta de consenso general desplaza la página a la parte superior, lo cual es una experiencia de usuario horrible. Deberías escribir un blog sobre esto. Terminé convirtiendo esto en una solución global.
Smith

Esto no funcionará en iphone.
BadriNarayanan Sridharan

6

No estoy seguro acerca de este código, pero vale la pena intentarlo.

En jQuery:

$(document).ready(function() {
    $(/* Put in your "onModalDisplay" here */)./* whatever */(function() {
        $("#Modal").css("overflow", "hidden");
    });
});

Como dije antes, no estoy 100% seguro pero lo intento de todos modos.


1
Esto no evita que el cuerpo se desplace mientras se abre el modal
xorinzor

@xorinzor usted dijo en la sección de comentarios de la respuesta de charlietfl que esto funciona. Pero usted dijo: Esto no impide que el cuerpo se desplace mientras se abre el modal.
Anish Gupta

cierto, pero por ahora es la única solución que funciona en parte y estoy de acuerdo. la razón por la que marqué su respuesta como respuesta es porque él fue antes con la respuesta.
xorinzor

@xorinzor realmente, pensé que había respondido antes que él / ella, podría ser un error extraño. aunque está bien
Anish Gupta


4

La mejor solución es la body{overflow:hidden}solución de solo CSS utilizada por la mayoría de estas respuestas. Algunas respuestas proporcionan una solución que también evita el "salto" causado por la barra de desplazamiento que desaparece; Sin embargo, ninguno era demasiado elegante. Entonces, escribí estas dos funciones, y parecen funcionar bastante bien.

var $body = $(window.document.body);

function bodyFreezeScroll() {
    var bodyWidth = $body.innerWidth();
    $body.css('overflow', 'hidden');
    $body.css('marginRight', ($body.css('marginRight') ? '+=' : '') + ($body.innerWidth() - bodyWidth))
}

function bodyUnfreezeScroll() {
    var bodyWidth = $body.innerWidth();
    $body.css('marginRight', '-=' + (bodyWidth - $body.innerWidth()))
    $body.css('overflow', 'auto');
}

Mira este jsFiddle para verlo en uso.


Esto no es tan viejo, pero nada de esto funciona para mí, ni siquiera el violín todavía puedo desplazar la ventana, ¿qué me estoy perdiendo?
aterrizó el

¡Abra y cierre el modal varias veces, y el DIV verde principal se encoge y encoge!
Webinan

@Webinan No veo esto en Chrome en Win7. ¿Cuál es el tamaño de su navegador y ventana gráfica?
Stephen M. Harris

1
@smhmic después de aproximadamente 20 veces de apertura y cierre, el ancho del div verde se vuelve igual al ancho de los open modalbotones. Chrome el 8
Webinan

Similar a la respuesta de @ jpap ( stackoverflow.com/a/16451821/5516499 ) pero con errores añadidos. :-(
Kivi Shapiro

4

Muchos sugieren "desbordamiento: oculto" en el cuerpo, que no funcionará (al menos no en mi caso), ya que hará que el sitio web se desplace hacia la parte superior.

Esta es la solución que funciona para mí (tanto en teléfonos móviles como en computadoras), usando jQuery:

    $('.yourModalDiv').bind('mouseenter touchstart', function(e) {
        var current = $(window).scrollTop();
        $(window).scroll(function(event) {
            $(window).scrollTop(current);
        });
    });
    $('.yourModalDiv').bind('mouseleave touchend', function(e) {
        $(window).off('scroll');
    });

Esto hará que el desplazamiento del modal funcione y evitará que el sitio web se desplace al mismo tiempo.


Parece que esta solución también corrige este error de iOS: hackernoon.com/…
Gotenks

3

Podrías usar la siguiente lógica, la probé y funciona (incluso en IE)

   <html>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">

var currentScroll=0;
function lockscroll(){
    $(window).scrollTop(currentScroll);
}


$(function(){

        $('#locker').click(function(){
            currentScroll=$(window).scrollTop();
            $(window).bind('scroll',lockscroll);

        })  


        $('#unlocker').click(function(){
            currentScroll=$(window).scrollTop();
            $(window).unbind('scroll');

        })
})

</script>

<div>

<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<button id="locker">lock</button>
<button id="unlocker">unlock</button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

</div>

2

No estoy 100% seguro de que esto funcione con Bootstrap, pero vale la pena intentarlo: funcionó con Remodal.js, que se puede encontrar en github: http://vodkabears.github.io/remodal/ y tendría sentido para los métodos para ser bastante similar

Para evitar que la página salte a la parte superior y también evitar el desplazamiento correcto del contenido, agregue una clase bodycuando se active el modal y establezca estas reglas CSS:

body.with-modal {
    position: static;
    height: auto;
    overflow-y: hidden;
}

Es el position:staticy el height:autoque se combinan para detener el salto de contenido a la derecha. El overflow-y:hidden;detiene la página de ser desplazable detrás del modal.


Esta solución me funciona perfectamente en Safari 11.1.1, Chrome 67.0.3396.99 y Firefox 60.0.2. ¡Gracias!
Dom

2

Basado en este violín: http://jsfiddle.net/dh834zgw/1/

el siguiente fragmento (usando jquery) deshabilitará el desplazamiento de la ventana:

 var curScrollTop = $(window).scrollTop();
 $('html').toggleClass('noscroll').css('top', '-' + curScrollTop + 'px');

Y en tu css:

html.noscroll{
    position: fixed;
    width: 100%;
    top:0;
    left: 0;
    height: 100%;
    overflow-y: scroll !important;
    z-index: 10;
 }

Ahora, cuando elimine el modal, no olvide eliminar la clase noscroll en la etiqueta html:

$('html').toggleClass('noscroll');

¿No overflowdebería establecerse en hidden? +1 aunque esto funcionó para mí (usando hidden).
mhulse

2

Tenía una barra lateral que fue generada por el hack de la casilla de verificación. Pero la idea principal es guardar el documento scrollTop y no cambiarlo durante el desplazamiento de la ventana.

Simplemente no me gustó el salto de página cuando el cuerpo se convierte en 'desbordamiento: oculto'.

window.addEventListener('load', function() {
    let prevScrollTop = 0;
    let isSidebarVisible = false;

    document.getElementById('f-overlay-chkbx').addEventListener('change', (event) => {
        
        prevScrollTop = window.pageYOffset || document.documentElement.scrollTop;
        isSidebarVisible = event.target.checked;

        window.addEventListener('scroll', (event) => {
            if (isSidebarVisible) {
                window.scrollTo(0, prevScrollTop);
            }
        });
    })

});


2

Lamentablemente, ninguna de las respuestas anteriores solucionó mis problemas.

En mi situación, la página web originalmente tenía una barra de desplazamiento. Cada vez que hago clic en el modal, la barra de desplazamiento no desaparecerá y el encabezado se moverá un poco hacia la derecha.

Luego intenté agregar .modal-open{overflow:auto;}(que la mayoría de la gente me recomendó). De hecho, solucionó los problemas: la barra de desplazamiento aparece después de abrir el modal. Sin embargo, surge otro efecto secundario que es que "el fondo debajo del encabezado se moverá un poco hacia la izquierda, junto con otra barra larga detrás del modal"

Barra larga detrás de modal

Afortunadamente, después de agregar {padding-right: 0 !important;}, todo se arregla perfectamente. Tanto el encabezado como el fondo del cuerpo no se movieron y el modal aún mantiene la barra de desplazamiento.

Imagen fija

Espero que esto pueda ayudar a aquellos que todavía están atrapados con este problema. ¡Buena suerte!


1

La mayoría de las piezas están aquí, pero no veo ninguna respuesta que lo ponga todo junto.

El problema es triple.

(1) evitar el desplazamiento de la página subyacente

$('body').css('overflow', 'hidden')

(2) y quite la barra de desplazamiento

var handler = function (e) { e.preventDefault() }
$('.modal').bind('mousewheel touchmove', handler)

(3) limpiar cuando se descarta el modal

$('.modal').unbind('mousewheel touchmove', handler)
$('body').css('overflow', '')

Si el modal no es de pantalla completa, aplique los enlaces .modal a una superposición de pantalla completa.


44
Esto también evita el desplazamiento dentro del modal.
Daniel

El mismo problema. ¿Encontraste una solución? @Daniel
AlexioVay

@Vay tipo de. Mira esto: blog.christoffer.me/…
Daniel

1

Mi solución para Bootstrap 3:

.modal {
  overflow-y: hidden;
}
body.modal-open {
  margin-right: 0;
}

porque para mí, el único overflow: hiddenen la body.modal-openclase no impidió que la página se moviera hacia la izquierda debido al original margin-right: 15px.


1

Lo acabo de hacer de esta manera ...

$('body').css('overflow', 'hidden');

Pero cuando desapareció el desplazador, movió todo bien 20px, así que agregué

$('body').css('margin-right', '20px');

justo después de eso.

Funciona para mi.


Esto solo funciona si el modal es más pequeño que el tamaño de la pantalla.
Sergey

1

Si el modal es 100% alto / ancho, "mouseenter / leave" funcionará para habilitar / deshabilitar fácilmente el desplazamiento. Esto realmente funcionó para mí:

var currentScroll=0;
function lockscroll(){
    $(window).scrollTop(currentScroll);
} 
$("#myModal").mouseenter(function(){
    currentScroll=$(window).scrollTop();
    $(window).bind('scroll',lockscroll); 
}).mouseleave(function(){
    currentScroll=$(window).scrollTop();
    $(window).unbind('scroll',lockscroll); 
});

1

trabajó para mi

$('#myModal').on({'mousewheel': function(e) 
    {
    if (e.target.id == 'el') return;
    e.preventDefault();
    e.stopPropagation();
   }
});

1

¿Por qué no hacer eso como hace Bulma? Cuando modal está activo, agregue a html su clase .is-clipped que está desbordada: hidden! Important; Y eso es.

Editar: Okey, Bulma tiene este error, por lo que debe agregar también otras cosas como

html.is-modal-active {
  overflow: hidden !important;
  position: fixed;
  width: 100%; 
}

1

Dado que para mí este problema se presenta principalmente en iOS, proporciono el código para solucionarlo solo en iOS:

  if(!!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)) {
    var $modalRep    = $('#modal-id'),
        startScrollY = null, 
        moveDiv;  

    $modalRep.on('touchmove', function(ev) {
      ev.preventDefault();
      moveDiv = startScrollY - ev.touches[0].clientY;
      startScrollY = ev.touches[0].clientY;
      var el = $(ev.target).parents('#div-that-scrolls');
      // #div-that-scrolls is a child of #modal-id
      el.scrollTop(el.scrollTop() + moveDiv);
    });

    $modalRep.on('touchstart', function(ev) {
      startScrollY = ev.touches[0].clientY;
    });
  }

1

Ninguna de las respuestas anteriores funcionó perfectamente para mí. Así que encontré otra forma que funciona bien.

Simplemente agregue un scroll.(namespace)oyente y un conjunto scrollTopdedocument a la última de su valor ...

y también elimine al oyente en su guión cercano.

// in case of bootstrap modal example:
$('#myModal').on('shown.bs.modal', function () {

  var documentScrollTop = $(document).scrollTop();
  $(document).on('scroll.noScroll', function() {
     $(document).scrollTop(documentScrollTop);
     return false;
  });

}).on('hidden.bs.modal', function() {

  $(document).off('scroll.noScroll');

});

actualizar

Parece que esto no funciona bien en Chrome. alguna sugerencia para solucionarlo?


0

Esto funcionó para mí:

$("#mymodal").mouseenter(function(){
   $("body").css("overflow", "hidden"); 
}).mouseleave(function(){
   $("body").css("overflow", "visible");
});

0

Para aquellos que se preguntan cómo obtener el evento de desplazamiento para el modal bootstrap 3:

$(".modal").scroll(function() {
    console.log("scrolling!);
});
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.