¿Cómo deshabilitar el desplazamiento temporalmente?

435

Estoy usando el plugin scrollTo jQuery y me gustaría saber si de alguna manera es posible deshabilitar temporalmente el desplazamiento en el elemento de la ventana a través de Javascript. La razón por la que me gustaría deshabilitar el desplazamiento es que cuando te desplazas mientras scrollTo está animando, se pone realmente feo;)

Por supuesto, podría hacer un $("body").css("overflow", "hidden");y luego volver a ponerlo en automático cuando la animación se detenga, pero sería mejor si la barra de desplazamiento todavía fuera visible pero inactiva.

Olivier Lalonde
fuente
12
Si todavía se muestra, el usuario está capacitado para pensar que debe estar funcionando. Si la dosis no se mueve o la dosis no responde, se romperá el modelo mental de los usuarios de cómo funciona su página y dará lugar a confusión. Simplemente encontraría una mejor manera de lidiar con el desplazamiento mientras se anima, como por ejemplo detener la animación.
Marcus Whybrow

Respuestas:

731

El scrollevento no puede ser cancelado. Pero puede hacerlo cancelando estos eventos de interacción:
mouse y Touch scroll y botones asociados con el desplazamiento.

[ Demo de trabajo ]

// left: 37, up: 38, right: 39, down: 40,
// spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36
var keys = {37: 1, 38: 1, 39: 1, 40: 1};

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

function preventDefaultForScrollKeys(e) {
  if (keys[e.keyCode]) {
    preventDefault(e);
    return false;
  }
}

// modern Chrome requires { passive: false } when adding event
var supportsPassive = false;
try {
  window.addEventListener("test", null, Object.defineProperty({}, 'passive', {
    get: function () { supportsPassive = true; } 
  }));
} catch(e) {}

var wheelOpt = supportsPassive ? { passive: false } : false;
var wheelEvent = 'onwheel' in document.createElement('div') ? 'wheel' : 'mousewheel';

// call this to Disable
function disableScroll() {
  window.addEventListener('DOMMouseScroll', preventDefault, false); // older FF
  window.addEventListener(wheelEvent, preventDefault, wheelOpt); // modern desktop
  window.addEventListener('touchmove', preventDefault, wheelOpt); // mobile
  window.addEventListener('keydown', preventDefaultForScrollKeys, false);
}

// call this to Enable
function enableScroll() {
  window.removeEventListener('DOMMouseScroll', preventDefault, false);
  window.removeEventListener(wheelEvent, preventDefault, wheelOpt); 
  window.removeEventListener('touchmove', preventDefault, wheelOpt);
  window.removeEventListener('keydown', preventDefaultForScrollKeys, false);
}

ACTUALIZACIÓN: escritorio Chrome fijo y navegadores móviles modernos con oyentes pasivos

gblazex
fuente
114
Sugerencia para otros desarrolladores atrapados en esta trampa: asegúrese de eliminar todas y cada una de las llamadas 'e.stopPropagation ()' de otros intentos de jQuery para detener el desplazamiento, porque no solo no funciona, sino que evita que el evento burbujee a ESTE código Eso sí funciona. Espero que mis 30 minutos desperdiciados ayuden a ahorrar tiempo a otra persona :)
Dirk van Bergen
44
Puede agregar 32 (espacio) a la matriz de teclas deshabilitadas (se muestra en los comentarios del código).
gblazex
14
Puedo desplazar esto como siempre: presionando el botón central y moviendo el mouse ... Por lo tanto, este truco no afectará a usuarios como yo;)
Denis V
11
La barra de desplazamiento no está deshabilitada.
verismo
8
Esto ya no funciona en Chrome
PerrierCitror
428

Hágalo simplemente agregando una clase al cuerpo:

.stop-scrolling {
  height: 100%;
  overflow: hidden;
}

Agregue la clase y luego elimine cuando desee volver a habilitar el desplazamiento, probado en IE, FF, Safari y Chrome.

$('body').addClass('stop-scrolling')

Para dispositivos móviles , deberá manejar el touchmoveevento:

$('body').bind('touchmove', function(e){e.preventDefault()})

Y desvinculate para volver a habilitar el desplazamiento. Probado en iOS6 y Android 2.3.3

$('body').unbind('touchmove')
hallodom
fuente
44
¡Entendido! Tienes que manejar el touchmoveevento, como con $('body').bind('touchmove', function(e){e.preventDefault()}). Editó esta respuesta para incluir esta solución móvil.
MusikAnimal
3
Genial, solo tienes que asegurarte de que cualquier desplazamiento interno pueda funcionar en el modo para el dispositivo táctil. Podría hacer una superposición justo debajo del modal y evitar el movimiento táctil predeterminado en la superposición en lugar del cuerpo.
Hallodom
63
Si bien esta solución funciona, tiene el efecto (potencialmente) no deseado de desplazarse hacia la parte superior de la página.
Matt
3
Esto no funcionó para mí a menos que mi selector fuera$('body,html')
PickYourPoison
22
Esta solución funciona, pero la barra de desplazamiento desaparece y crea un efecto de "golpe" (debajo de la ventana del sistema operativo) cuando aplica esta clase al cuerpo (por ejemplo)
Georgio
57

Aquí hay una forma realmente básica de hacerlo:

window.onscroll = function () { window.scrollTo(0, 0); };

Es un poco nervioso en IE6.

sdleihssirhc
fuente
14
Realmente no es una desactivación, más bien un ajuste predeterminado cuando se intenta el desplazamiento.
Marcus Whybrow
11
@Marcus Tan bueno como será con un evento que no se puede cancelar.
sdleihssirhc
3
Aunque no lo deshabilita de verdad, lo simula y eso es lo suficientemente bueno para mí.
Chris Bier
11
En mi humilde opinión, la mejor respuesta aquí. Además, no tiene que bloquearlo (0, 0), solo use la posición de desplazamiento actual.
YemSalat
44
¿Pero cómo lo volvemos a habilitar?
Cibernético el
41

La siguiente solución es JavaScript básico pero puro (sin jQuery):

function disableScrolling(){
    var x=window.scrollX;
    var y=window.scrollY;
    window.onscroll=function(){window.scrollTo(x, y);};
}

function enableScrolling(){
    window.onscroll=function(){};
}
Mohammad Anini
fuente
3
Jumpy en Safari 7.1 e IE 11. El más nuevo Chrome, Firefox, Opera ok.
Timo Kähkönen
Todavía un poco nervioso en el nuevo Chrome
Jason Allshorn el
Trabajando bien, en safari, cromo, pero parpadeó en IE
Bhuvan Arora
Si esta solución no funciona para algún navegador, entonces ese es un problema de navegadores
Oto Shavadze
Como se mencionó en otra respuesta, scroll-behavior: smooth Bork esto. Además, no estoy de acuerdo con Oto diciendo que es culpa del navegador. Básicamente estás asumiendo que algo sucederá instantáneamente cuando en realidad es asíncrono
Matt Fletcher
25

Esta solución mantendrá la posición de desplazamiento actual mientras el desplazamiento esté deshabilitado, a diferencia de algunos que vuelven al usuario a la cima.

Se basa en la respuesta de galambalazs , pero con soporte para dispositivos táctiles, y se refactoriza como un solo objeto con jquery plugin wrapper.

Demostración aquí.

En github aquí.

/**
 * $.disablescroll
 * Author: Josh Harrison - aloof.co
 *
 * Disables scroll events from mousewheels, touchmoves and keypresses.
 * Use while jQuery is animating the scroll position for a guaranteed super-smooth ride!
 */

;(function($) {

    "use strict";

    var instance, proto;

    function UserScrollDisabler($container, options) {
        // spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36
        // left: 37, up: 38, right: 39, down: 40
        this.opts = $.extend({
            handleKeys : true,
            scrollEventKeys : [32, 33, 34, 35, 36, 37, 38, 39, 40]
        }, options);

        this.$container = $container;
        this.$document = $(document);
        this.lockToScrollPos = [0, 0];

        this.disable();
    }

    proto = UserScrollDisabler.prototype;

    proto.disable = function() {
        var t = this;

        t.lockToScrollPos = [
            t.$container.scrollLeft(),
            t.$container.scrollTop()
        ];

        t.$container.on(
            "mousewheel.disablescroll DOMMouseScroll.disablescroll touchmove.disablescroll",
            t._handleWheel
        );

        t.$container.on("scroll.disablescroll", function() {
            t._handleScrollbar.call(t);
        });

        if(t.opts.handleKeys) {
            t.$document.on("keydown.disablescroll", function(event) {
                t._handleKeydown.call(t, event);
            });
        }
    };

    proto.undo = function() {
        var t = this;
        t.$container.off(".disablescroll");
        if(t.opts.handleKeys) {
            t.$document.off(".disablescroll");
        }
    };

    proto._handleWheel = function(event) {
        event.preventDefault();
    };

    proto._handleScrollbar = function() {
        this.$container.scrollLeft(this.lockToScrollPos[0]);
        this.$container.scrollTop(this.lockToScrollPos[1]);
    };

    proto._handleKeydown = function(event) {
        for (var i = 0; i < this.opts.scrollEventKeys.length; i++) {
            if (event.keyCode === this.opts.scrollEventKeys[i]) {
                event.preventDefault();
                return;
            }
        }
    };


    // Plugin wrapper for object
    $.fn.disablescroll = function(method) {

        // If calling for the first time, instantiate the object and save
        // reference. The plugin can therefore only be instantiated once per
        // page. You can pass options object in through the method parameter.
        if( ! instance && (typeof method === "object" || ! method)) {
            instance = new UserScrollDisabler(this, method);
        }

        // Instance already created, and a method is being explicitly called,
        // e.g. .disablescroll('undo');
        else if(instance && instance[method]) {
            instance[method].call(instance);
        }

    };

    // Global access
    window.UserScrollDisabler = UserScrollDisabler;

})(jQuery);
Josh Harrison
fuente
Me alegra que sea útil. Nota: he editado con un enlace a esto en formato de complemento jQuery .
Josh Harrison el
Podría ayudar si el botón de desplazamiento de desactivación realmente funcionara
cameronjonesweb
@ user1672694, funciona aquí en Chrome. ¿Cuál es su navegador y en qué página de demostración ha encontrado el error? ¿Algún error JS en la consola?
Josh Harrison
En Chrome (38, Windows 7), aún puedo desplazarme haciendo clic y manteniendo presionado el botón central y luego arrastrando.
Sethi
1
Por favor ignore, encontré que la unión mousewheelfuncionó de
maravilla
17

Lamento responder una publicación anterior, pero estaba buscando una solución y encontré esta pregunta.

Hay muchas soluciones para que este problema muestre la barra de desplazamiento, como darle al contenedor una altura del 100% y un overflow-y: scroll estilo.

En mi caso, acabo de crear un div con una barra de desplazamiento que visualizo mientras agrego overflow: hiddenal cuerpo:

function disableScroll() {
    document.getElementById('scrollbar').style.display = 'block';
    document.body.style.overflow = 'hidden';
}

La barra de desplazamiento del elemento debe tener estos estilos:

overflow-y: scroll; top: 0; right: 0; display: none; height: 100%; position: fixed;

Esto muestra una barra de desplazamiento gris, espero que ayude a futuros visitantes.

lisovaccaro
fuente
8

Estaba buscando una solución a este problema, pero no estaba satisfecho con ninguna de las soluciones anteriores ( al momento de escribir esta respuesta ), así que se me ocurrió esta solución.

CSS

.scrollDisabled {   
    position: fixed;
    margin-top: 0;// override by JS to use acc to curr $(window).scrollTop()
    width: 100%;
}

JS

var y_offsetWhenScrollDisabled=0;

function disableScrollOnBody(){
    y_offsetWhenScrollDisabled= $(window).scrollTop();
    $('body').addClass('scrollDisabled').css('margin-top', -y_offsetWhenScrollDisabled);
}
function enableScrollOnBody(){
    $('body').removeClass('scrollDisabled').css('margin-top', 0);
    $(window).scrollTop(y_offsetWhenScrollDisabled);
}
Rajat Gupta
fuente
Encontré que esto funcionaba para mí si añadía overflow-y: scrollal .scrollDisabledestilo. De lo contrario, hubo un pequeño salto cuando la barra de desplazamiento se ocultó cada vez. Por supuesto, eso solo funciona para mí porque mi página es lo suficientemente larga como para necesitar una barra de desplazamiento incluso en las pantallas más grandes.
Andrew Miner
7

Según la publicación de galambalazs , agregaría soporte para dispositivos táctiles, lo que nos permite tocar pero no desplazarnos hacia arriba o hacia abajo:

function disable_scroll() {
   ...
   document.ontouchmove = function(e){ 
        e.preventDefault(); 
   }
}

function enable_scroll() {
   ...
   document.ontouchmove = function(e){ 
     return true; 
   }
}
jvalen
fuente
3
¿Estás seguro de que es una respuesta, no solo un comentario de otra respuesta?
IvanH
6

A partir de Chrome 56 y otros navegadores modernos, debe agregar passive:falsea la addEventListenerllamada para que preventDefaultfuncione. Así que uso esto para detener el desplazamiento en el móvil:

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

function disableScroll(){
    document.body.addEventListener('touchmove', preventDefault, { passive: false });
}
function enableScroll(){
    document.body.removeEventListener('touchmove', preventDefault, { passive: false });
}
Hokascha
fuente
5

No, no iría con el manejo de eventos porque:

  • no todos los eventos están garantizados para llegar al cuerpo,

  • seleccionar texto y moverse hacia abajo en realidad desplaza el documento,

  • si en la fase del evento, separar algo sale mal, estás condenado.

He mordido esto haciendo una acción de copiar y pegar con un área de texto oculta y adivina qué, la página se desplaza cada vez que hago una copia porque internamente tengo que seleccionar el área de texto antes de llamar document.execCommand('copy').

De todos modos, así es como me dirijo, fíjate en setTimeout():

document.body.setAttribute('style','overflow:hidden;');
// do your thing...
setTimeout(function(){document.body.setAttribute('style','overflow:visible;');}, 500);

Existe un impulso intermitente cuando las barras de desplazamiento desaparecen momentáneamente, pero es aceptable.

centurias
fuente
4

Dependiendo de lo que desee lograr con el desplazamiento eliminado, puede simplemente arreglar el elemento del que desea eliminar el desplazamiento (al hacer clic o cualquier otro activador que desee desactivar temporalmente el desplazamiento)

Estaba buscando una solución "temp no scroll" y para mis necesidades, esto lo resolvió

hacer una clase

.fixed{
    position: fixed;
}

luego con Jquery

var someTrigger = $('#trigger'); //a trigger button
var contentContainer = $('#content'); //element I want to temporarily remove scroll from

contentContainer.addClass('notfixed'); //make sure that the element has the "notfixed" class

//Something to trigger the fixed positioning. In this case we chose a button.
someTrigger.on('click', function(){

    if(contentContainer.hasClass('notfixed')){
        contentContainer.removeClass('notfixed').addClass('fixed');

    }else if(contentContainer.hasClass('fixed')){
        contentContainer.removeClass('fixed').addClass('notfixed');
    };
});

Descubrí que esta era una solución lo suficientemente simple que funciona bien en todos los navegadores, y también es fácil de usar en dispositivos portátiles (es decir, iPhones, tabletas, etc.). Dado que el elemento está temporalmente arreglado, no hay desplazamiento :)

¡NOTA! Dependiendo de la ubicación de su elemento "contentContainer", es posible que deba ajustarlo desde la izquierda. Lo que se puede hacer fácilmente agregando un valor izquierdo css a ese elemento cuando la clase fija está activa

contentContainer.css({
    'left': $(window).width() - contentContainer.width()/2 //This would result in a value that is the windows entire width minus the element we want to "center" divided by two (since it's only pushed from one side)
});
axelra82
fuente
4

Otra solución:

body {
    overflow-y: scroll;
    width: 100%;
    margin: 0 auto;
}

De esta manera, siempre tiene una barra de desplazamiento vertical, pero como la mayoría de mi contenido es más largo que la ventana gráfica, esto está bien para mí. El contenido está centrado con un div separado, pero sin volver a establecer el margen en el cuerpo, mi contenido se quedaría a la izquierda.

Estas son las dos funciones que uso para mostrar mi ventana emergente / modal:

var popup_bodyTop = 0;
var popup_bodyLeft = 0;

function popupShow(id)
{
    $('#'+ id).effect('fade');
    $('#popup-overlay').effect('fade');

    // remember current scroll-position
    // because when setting/unsetting position: fixed to body
    // the body would scroll to 0,0
    popup_bodyLeft = $(document).scrollLeft();
    popup_bodyTop  = $(document).scrollTop();

    // invert position
    var x = - popup_bodyLeft;
    var y = - popup_bodyTop;

    $('body').css('position', 'fixed');
    $('body').css('top', y.toString() +'px');
    $('body').css('left', x.toString() +'px');
}

function popupHide(id)
{
    $('#'+ id).effect('fade');
    $('#popup-overlay').effect('fade');
    $('body').css('position', '');
    $('html, body').scrollTop(popup_bodyTop);
    $('html, body').scrollLeft(popup_bodyLeft);
}

Resultado: fondo no desplazable y sin reubicación del contenido debido a la barra de desplazamiento izquierda. Probado con FF actual, Chrome e IE 10.

Marco
fuente
Esto funcionó para mí y el problema de desplazarse hacia la parte superior después de usar position: fixed. ¡Gracias!
Annia Martinez
3

¿Qué tal esto? (Si estás usando jQuery)

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

window.onscroll = function() {
    var overlay = $body.children(".ui-widget-overlay").first();

    // Check if the overlay is visible and restore the previous scroll state
    if (overlay.is(":visible")) {
        var scrollPos = $body.data("scroll-pos") || { x: 0, y: 0 };
        window.scrollTo(scrollPos.x, scrollPos.y);
    }
    else {
        // Just store the scroll state
        $body.data("scroll-pos", { x: $window.scrollLeft(), y: $window.scrollTop() });
    }
};
Dan
fuente
un poco nervioso, pero esto funciona para IE 7 (el cliente lo usa). otras soluciones no.
niki b
3

Estoy usando showModalDialog , para mostrar la página secundaria como diálogo modal.

para ocultar las barras de desplazamiento de la ventana principal:

document.body.style.overflow = "hidden";

y al cerrar el diálogo modal, que muestra las barras de desplazamiento de la ventana principal:

document.body.style.overflow = "scroll";

para acceder a elementos en la ventana principal desde el diálogo:

parent.document.getElementById('dialog-close').click();

solo para cualquiera que busque sobre showModalDialog : (después de la línea 29 del código original)

document.getElementById('dialog-body').contentWindow.dialogArguments = arg;
document.body.style.overflow = "hidden";//****
document.getElementById('dialog-close').addEventListener('click', function(e) {
    e.preventDefault();
    document.body.style.overflow = "scroll";//****
    dialog.close();
});
Zolfaghari
fuente
Esto funcionó para mí en React, donde jQuery no existe y donde React no tiene acceso para administrar el estado de la etiqueta del cuerpo.
Jon
3

Cancelar el evento como en la respuesta aceptada es un método horrible en mi opinión: /

En su lugar, utilicé a position: fixed; top: -scrollTop();continuación.

Demostración: https://jsfiddle.net/w9w9hthy/5/

Desde mi proyecto emergente jQuery: https://github.com/seahorsepip/jPopup

//Freeze page content scrolling
function freeze() {
    if($("html").css("position") != "fixed") {
        var top = $("html").scrollTop() ? $("html").scrollTop() : $("body").scrollTop();
        if(window.innerWidth > $("html").width()) {
            $("html").css("overflow-y", "scroll");
        }
        $("html").css({"width": "100%", "height": "100%", "position": "fixed", "top": -top});
    }
}

//Unfreeze page content scrolling
function unfreeze() {
    if($("html").css("position") == "fixed") {
        $("html").css("position", "static");
        $("html, body").scrollTop(-parseInt($("html").css("top")));
        $("html").css({"position": "", "width": "", "height": "", "top": "", "overflow-y": ""});
    }
}

Este código toma en consideración los problemas de ancho, alto, barra de desplazamiento y salto de página.

Posibles problemas resueltos con el código anterior:

  • ancho, al establecer la posición fija, el ancho del elemento html puede ser menor que 100%
  • altura, igual que arriba
  • barra de desplazamiento, al establecer la posición fija, el contenido de la página ya no tiene una barra de desplazamiento, incluso cuando tenía una barra de desplazamiento antes de dar como resultado un salto de página horizontal
  • salto de página, cuando se fija la posición fija, el desplazamiento de página superior ya no es efectivo, lo que resulta en un salto de página vertical

Si alguien tiene alguna mejora en el código de congelación / descongelación de la página anterior, avíseme para que pueda agregar esas mejoras a mi proyecto.

caballito de mar
fuente
3
var winX = null, winY = null;
window.addEventListener('scroll', function () {
    if (winX !== null && winY !== null) {
        window.scrollTo(winX, winY);
    }
});
function disableWindowScroll() {
    winX = window.scrollX;
    winY = window.scrollY;
};
function enableWindowScroll() {
    winX = null;
    winY = null;
};
Văn Quyết
fuente
1
Esta es la mejor solución aquí.
jfunk
@jfunk de acuerdo, simple y conciso, código pequeño, perfecto. Gracias
Florent Roques
2

Tengo el mismo problema, a continuación se muestra la forma en que lo manejo.

/* file.js */
var body = document.getElementsByTagName('body')[0];
//if window dont scroll
body.classList.add("no-scroll");
//if window scroll
body.classList.remove("no-scroll");

/* file.css */
.no-scroll{
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

espero que esto ayude.

Robert
fuente
1

Sobre la base de la respuesta de Cheyenne Forbes, y una que encontré aquí a través de fcalderan: ¿Deshabilitar el desplazamiento, no ocultarlo? y para arreglar el problema de Hallodom de la barra de desplazamiento desapareciendo

CSS:

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

JS:

whatever.onclick = function(){
    $('body').addClass('preventscroll');
}
whatevertoclose.onclick = function(){
    $('body').removeClass('preventscroll');
}

Este código lo lleva a la parte superior de la página, pero creo que el código de fcalderan tiene una solución alternativa.

Sutileza
fuente
1

Sé que esta es una vieja pregunta, pero tuve que hacer algo muy similar, y después de un tiempo buscando una respuesta e intentando diferentes enfoques, terminé usando una solución muy fácil.

Mi problema era muy similar, casi idéntico, la única diferencia es que no tenía que mostrar realmente la barra de desplazamiento; solo tenía que asegurarme de que su ancho aún se usaría, para que el ancho de la página no cambiara mientras se mostraba mi superposición .

Cuando comienzo a deslizar mi superposición en la pantalla, hago:

$('body').addClass('stop-scrolling').css('margin-right', 8);

y después de deslizar mi superposición fuera de la pantalla hago:

$('body').removeClass('stop-scrolling').css('margin-right', 0);

IMPORTANTE: esto funciona perfectamente porque mi superposición está posicionada absolute, right: 0pxcuando visible.

usuario2430829
fuente
1

El método más simple es:

$("body").css("overflow", "hidden"); // Remove the scroll bar temporarily

Para deshacerlo:

$("body").css("overflow", "auto");

Fácil de implementar, pero el único inconveniente es:

  • La página saltará un poco hacia la izquierda si está alineada al centro (horizontalmente).

Esto se debe a la eliminación de la barra de desplazamiento y a que la vista se vuelve un poco más ancha.

Daan
fuente
1
eso restablecerá la posición de desplazamiento
Angel David Calderaro Pacciott
@AngelDavidCalderaroPacciott No, la posición de desplazamiento seguirá siendo la misma altura / distancia.
Daan
@Daan restablece la posición de desplazamiento en Chrome
Tom
@Tom Lo acabo de comprobar, solo lo hace en algunas ocasiones (cuando la altura del cuerpo no es relativa a sus hijos). Intenta cambiar bodya en su htmllugar.
Daan
Apuesto a que no comprobaste tu solución en Iphone porque overflow:hiddenno funciona allí
Shuvo
1

Aquí está mi solución para detener el desplazamiento (sin jQuery). Lo uso para deshabilitar el desplazamiento cuando aparece el menú lateral.

<button onClick="noscroll()" style="position:fixed; padding: 8px 16px;">Disable/Enable scroll</button>
<script>
var noscroll_var;
function noscroll(){
  if(noscroll_var){
    document.getElementsByTagName("html")[0].style.overflowY = "";
    document.body.style.paddingRight = "0";
    noscroll_var = false
  }else{
    document.getElementsByTagName("html")[0].setAttribute('style', 'overflow-y: hidden !important');
    document.body.style.paddingRight = "17px";
    noscroll_var = true
  }
}/*noscroll()*/
</script>

<!-- Just to fill the page -->
<script>
  for(var i=0; i <= 80; i++){
    document.write(i + "<hr>")
  }
</script>

Puse 17 píxeles de relleno a la derecha para compensar la desaparición de la barra de desplazamiento. Pero esto también es problemático, principalmente para los navegadores móviles. Resuelto obteniendo el ancho de la barra de acuerdo con esto .

Todos juntos en esta pluma.

Josep81
fuente
1

Esta es la solución más simple que obtuve hasta ahora. Y créeme, probé todos los demás y este es el más fácil. Funciona muy bien en dispositivos Windows , lo que empuja la página desde la derecha para tener espacio para la barra de desplazamiento del sistema y los dispositivos IOS que no requieren espacio para sus barras de desplazamiento en los navegadores. Por lo tanto, al usar esto, no necesitará agregar relleno a la derecha para que la página no parpadee cuando oculte el desbordamiento del cuerpo o html con css .

La solución es bastante simple si lo piensas. La idea es darle a window.scrollTop () la misma posición exacta en el momento en que se abre una ventana emergente. También cambie esa posición cuando la ventana cambie de tamaño (ya que la posición de desplazamiento cambia una vez que eso sucede).

Así que, aquí vamos...

Primero, creemos la variable que le permitirá saber que la ventana emergente está abierta y la llamaremos stopWindowScroll . Si no hacemos esto, obtendrá un error de una variable indefinida en su página y lo configurará en 0, como no activo.

$(document).ready(function(){
    stopWindowScroll = 0;
});

Ahora hagamos que la función de ventana emergente abierta sea cualquier función en su código que active cualquier ventana emergente que esté usando como complemento o personalizada. En este caso, será una ventana emergente personalizada simple con un documento simple en función de clic.

$(document).on('click','.open-popup', function(){
    // Saving the scroll position once opening the popup.
    stopWindowScrollPosition = $(window).scrollTop();
    // Setting the stopWindowScroll to 1 to know the popup is open.
    stopWindowScroll = 1;
    // Displaying your popup.
    $('.your-popup').fadeIn(300);
});

Entonces, lo siguiente que hacemos es crear la función emergente de cierre, que repito nuevamente puede ser cualquier función que ya haya creado o esté utilizando en un complemento. Lo importante es que necesitamos esas 2 funciones para establecer la variable stopWindowScroll en 1 o 0 para saber cuándo está abierta o cerrada.

$(document).on('click','.open-popup', function(){
    // Setting the stopWindowScroll to 0 to know the popup is closed.
    stopWindowScroll = 0;
    // Hiding your popup
    $('.your-popup').fadeOut(300);
});

Luego, creemos la función window.scroll para que podamos evitar el desplazamiento una vez que stopWindowScroll mencionado anteriormente se establezca en 1, como activo.

$(window).scroll(function(){
    if(stopWindowScroll == 1) {
         // Giving the window scrollTop() function the position on which
         // the popup was opened, this way it will stay in its place.
         $(window).scrollTop(stopWindowScrollPosition);
    }
});

Eso es. No se requiere CSS para que esto funcione, excepto sus propios estilos para la página. Esto funcionó a las mil maravillas para mí y espero que les ayude a usted y a los demás.

Aquí hay un ejemplo de trabajo en JSFiddle:

JS Fiddle Example

Hagame saber si esto fue de utilidad. Saludos.

Arquitecto
fuente
1

¡Almacene la longitud de desplazamiento en una variable global y restaure cuando sea necesario!

var sctollTop_length = 0;

function scroll_pause(){
  sctollTop_length = $(window).scrollTop();
  $("body").css("overflow", "hidden");
}

function scroll_resume(){
  $("body").css("overflow", "auto");
  $(window).scrollTop(sctollTop_length);
}
Kareem
fuente
1

Este código funcionará en Chrome 56 y más (la respuesta original ya no funciona en Chrome).

Utilizar DomUtils.enableScroll() para habilitar el desplazamiento.

Use DomUtils.disableScroll()para deshabilitar el desplazamiento.

class DomUtils {
  // left: 37, up: 38, right: 39, down: 40,
  // spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36
  static keys = { 37: 1, 38: 1, 39: 1, 40: 1 };

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

  static preventDefaultForScrollKeys(e) {
    if (DomUtils.keys[e.keyCode]) {
      DomUtils.preventDefault(e);
      return false;
    }
  }

  static disableScroll() {
    document.addEventListener('wheel', DomUtils.preventDefault, {
      passive: false,
    }); // Disable scrolling in Chrome
    document.addEventListener('keydown', DomUtils.preventDefaultForScrollKeys, {
      passive: false,
    });
  }

  static enableScroll() {
    document.removeEventListener('wheel', DomUtils.preventDefault, {
      passive: false,
    }); // Enable scrolling in Chrome
    document.removeEventListener(
      'keydown',
      DomUtils.preventDefaultForScrollKeys,
      {
        passive: false,
      }
    ); // Enable scrolling in Chrome
  }
}
PerrierCitror
fuente
1

Para evitar el salto, esto es lo que usé

export function toggleBodyScroll(disable) {
  if (!window.tempScrollTop) {
    window.tempScrollTop = window.pageYOffset; 
    // save the current position in a global variable so I can access again later

  }
  if (disable) {
    document.body.classList.add('disable-scroll');
    document.body.style.top = `-${window.tempScrollTop}px`;
  } else {
    document.body.classList.remove('disable-scroll');
    document.body.style.top = `0px`;
    window.scrollTo({top: window.tempScrollTop});
    window.tempScrollTop = 0;
  }
}

y en mi css

.disable-scroll {
  height: 100%;
  overflow: hidden;
  width: 100%;
  position: fixed;
}
Milad
fuente
0

Encontré esta respuesta en otro sitio :

Deshabilitar desplazamiento:

$( ".popup").live({
    popupbeforeposition: function(event, ui) {
    $("body").on("touchmove", false);
}
});

Después de cerrar la ventana emergente, desplácese:

$( ".popup" ).live({
    popupafterclose: function(event, ui) {
    $("body").unbind("touchmove");
}
});
Pennstump
fuente
Eso solo parece detener el desplazamiento táctil, pero el desplazamiento del mouse, las teclas de flecha, las teclas de avance y retroceso de página, etc. seguirán funcionando. -1
markasoftware
Estos 'eventos' son para el desplazamiento táctil, solo sustituya los eventos que necesite.
pennstump
1
Además, esto parece ser utilizado en alguna otra situación muy específica. popupbeforeposition? ¿Para qué se supone que es eso? ¿Qué tiene esto que ver con desactivar temporalmente el desplazamiento? Al menos hazlo relevante para esta situación. Parece que copiaste esto directamente de un sitio web.
markasoftware
0

¡La solución de galambalazs es genial! Funcionó perfectamente para mí en Chrome y Firefox. Y también se puede extender para evitar cualquier evento predeterminado desde la ventana del navegador. Digamos que está haciendo una aplicación en el lienzo. Podrías hacer esto:

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

  //spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36,
  //left: 37, up: 38, right: 39, down: 40
  keys: [32, 33, 34, 35, 36, 37, 38, 39, 40],
  keydown: function(e) {
    for (var i = events.keys.length; i--;) {
      if (e.keyCode === events.keys[i]) {
        events.preventDefault(e);
        return;
      }
    }
  },

  wheel: function(e) {
    events.preventDefault(e);
  },

  disable: function() {
    if (window.addEventListener) {
      window.addEventListener('DOMMouseScroll', events.wheel, false);
    }
    window.onmousewheel = document.onmousewheel = events.wheel;
    document.onkeydown = helpers.events.keydown;
  },

  enable: function() {
    if (window.removeEventListener) {
      window.removeEventListener('DOMMouseScroll', events.wheel, false);
    }
    window.onmousewheel = document.onmousewheel = document.onkeydown = null;  
  }
}

Y luego, en su aplicación, digamos que va a procesar sus propios eventos, como el mouse, el teclado, los eventos táctiles, etc. sale:

function setMouseEvents(canvas) {
  var useCapture = false;

  //Mouse enter event
  canvas.addEventListener('mouseenter', function(event) {
    events.disable();
  }, useCapture);

  //Mouse leave event
  canvas.addEventListener('mouseleave', function(event) {
    events.enable();
  }, useCapture);
}

Incluso podría deshabilitar el menú del botón derecho con este truco:

function disableRightClickMenu(canvas) {
  var my_gradient = canvas.context.createLinearGradient(0, 0, 0, 225);
  my_gradient.addColorStop(0, "white");
  my_gradient.addColorStop(1, "white");
  canvas.context.fillStyle = my_gradient;
  canvas.context.fillRect(0, 0, canvas.width, canvas.height);
  canvas.oncontextmenu = function() { return false; };
}
Rafael
fuente
0

Tuve un problema de animación similar en pantallas móviles pero no en computadoras portátiles, cuando trataba de animar un div usando el comando animado de jquery. Entonces decidí usar un temporizador que restaurara la posición de desplazamiento de la ventana con tanta frecuencia que a simple vista el documento parecería estático. Esta solución funcionó perfectamente en un dispositivo móvil de pantalla pequeña como Samsung Galaxy-2 o iphone-5.

Lógica principal de este enfoque : el temporizador para establecer la posición de desplazamiento de la ventana en la posición de desplazamiento original debe iniciarse antes del comando jquery animate, y luego, cuando se complete la animación, necesitamos borrar este temporizador ( original scroll positiones la posición justo antes de que comience la animación).

Para mi sorpresa agradable, encontré que el documento realmente parecía estático durante la duración de la animación si el intervalo del temporizador era 1 millisecond, que es a lo que estaba apuntando.

//get window scroll position prior to animation
//so we can keep this position during animation
var xPosition = window.scrollX || window.pageXOffset || document.body.scrollLeft;
var yPosition = window.scrollY || window.pageYOffset || document.body.scrollTop;

//NOTE:restoreTimer needs to be global variable
//start the restore timer
restoreTimer = setInterval(function() {
    window.scrollTo(xPosition, yPosition);
}, 1);

//animate the element emt
emt.animate({
    left: "toggle",
    top: "toggle",
    width: "toggle",
    height: "toggle"
}, 500, function() {
    //when animation completes, we stop the timer
    clearInterval(restoreTimer);
});

OTRA SOLUCIÓN que funcionó : según la respuesta de Mohammad Anini en esta publicación para habilitar / deshabilitar el desplazamiento, también encontré que una versión modificada del código, como se muestra a continuación, funcionó.

//get current scroll position
var xPosition = window.scrollX || window.pageXOffset || document.body.scrollLeft;
var yPosition = window.scrollY || window.pageYOffset || document.body.scrollTop;

//disable scrolling
window.onscroll = function() {
    window.scrollTo(xPosition, yPosition);
};

//animate and enable scrolling when animation is completed
emt.animate({
    left: "toggle",
    top: "toggle",
    width: "toggle",
    height: "toggle"
}, 500, function() {
    //enable scrolling when animation is done
    window.onscroll = function() {};
});
Sunil
fuente
0

Una solución simple que funcionó para mí (deshabilitar el desplazamiento de la ventana temporalmente).

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');
abadejo
fuente