Comment désactiver temporairement le défilement?

435

J'utilise le plugin scrollTo jQuery et je voudrais savoir s'il est possible de désactiver temporairement le défilement de l'élément window via Javascript? La raison pour laquelle je voudrais désactiver le défilement est que lorsque vous faites défiler pendant que scrollTo est en cours d'animation, cela devient vraiment moche;)

Bien sûr, je pourrais faire un $("body").css("overflow", "hidden");puis le remettre sur auto lorsque l'animation s'arrête, mais il serait préférable que la barre de défilement soit toujours visible mais inactive.

Olivier Lalonde
la source
12
S'il continue de s'afficher, l'utilisateur est alors formé à penser qu'il doit fonctionner. Si la dose ne bouge pas ou que la dose ne répond pas, cela brisera le modèle mental des utilisateurs sur le fonctionnement de votre page et entraînera de la confusion. Je trouverais simplement une meilleure façon de gérer le défilement pendant l'animation, comme par exemple arrêter l'animation.
Marcus Whybrow
Une autre solution: stackoverflow.com/questions/9280258/…
gdbj

Réponses:

731

L' scrollévénement ne peut pas être annulé. Mais vous pouvez le faire en annulant ces événements d'interaction: défilement de la
souris et toucher et boutons associés au défilement.

[ Démo de travail ]

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

MISE À JOUR: bureau Chrome fixe et navigateurs mobiles modernes avec écouteurs passifs

gblazex
la source
114
Astuce pour les autres développeurs coincés dans ce piège: assurez-vous de supprimer tous les appels 'e.stopPropagation ()' des autres tentatives jQuery pour arrêter le défilement, car non seulement cela ne fonctionne pas, mais cela empêche l'événement de se propager à ce code qui fonctionne. J'espère que mes 30 minutes perdues aideront à faire gagner du temps à quelqu'un d'autre :)
Dirk van Bergen
4
Vous pouvez ajouter 32 (espace) au tableau des clés désactivées (voir dans les commentaires du code).
gblazex
14
Je peux faire défiler cela comme je le fais toujours: en appuyant sur le bouton du milieu et en déplaçant la souris ... Par conséquent, cette astuce n'affectera pas des utilisateurs comme moi;)
Denis V
11
La barre de défilement n'est pas désactivée.
verism
8
Cela ne fonctionne plus sur Chrome
PerrierCitror
428

Faites-le simplement en ajoutant une classe au corps:

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

Ajoutez la classe puis supprimez lorsque vous souhaitez réactiver le défilement, testé dans IE, FF, Safari et Chrome.

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

Pour les appareils mobiles , vous devrez gérer l' touchmoveévénement:

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

Et dissociez pour réactiver le défilement. Testé dans iOS6 et Android 2.3.3

$('body').unbind('touchmove')
hallodome
la source
4
Je l'ai! Vous devez gérer l' touchmoveévénement, comme avec $('body').bind('touchmove', function(e){e.preventDefault()}). Modifié cette réponse pour inclure cette solution mobile.
MusikAnimal
3
Cool, il suffit de s'assurer que tout défilement intérieur peut fonctionner dans le modal de l'appareil tactile. Pourrait faire une superposition juste en dessous du modal et empêcher le déplacement tactile par défaut sur la superposition au lieu du corps.
hallodom
63
Bien que cette solution fonctionne, elle a pour effet (potentiellement) indésirable de revenir en haut de la page.
Matt
3
Cela n'a pas fonctionné pour moi à moins que mon sélecteur ne soit$('body,html')
PickYourPoison
22
Cette solution fonctionne mais la barre de défilement disparaît et crée un effet de «bosse» (sous la fenêtre OS) lorsque vous appliquez cette classe au corps (par exemple)
Georgio
57

Voici une façon vraiment simple de le faire:

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

C'est un peu nerveux dans IE6.

sdleihssirhc
la source
14
Pas vraiment une désactivation, plus comme un accrochage par défaut lorsque le défilement est tenté.
Marcus Whybrow
11
@Marcus Aussi bien que cela va se passer avec un événement qui n'est pas annulable.
sdleihssirhc
3
Même s'il ne le désactive pas pour de vrai, il le simule et c'est assez bon pour moi.
Chris Bier
11
IMHO - meilleure réponse ici. De plus, vous n'avez pas à le verrouiller (0, 0), utilisez simplement la position de défilement actuelle.
YemSalat
4
Mais comment le réactiver?
Cybernetic
41

La solution suivante est un JavaScript basique mais pur (pas de 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
la source
3
Jumpy dans Safari 7.1 et IE 11. Chrome, Firefox, Opera les plus récents.
Timo Kähkönen
Encore un peu nerveux sur le dernier Chrome
Jason Allshorn
Fonctionne très bien, en safari, chrome, mais vacillait dans IE
Bhuvan Arora
Si cette solution ne fonctionne pas pour certains navigateurs, alors c'est le problème des navigateurs
Oto Shavadze
Comme mentionné dans une autre réponse, scroll-behavior: smoothça bouge. De plus, je ne suis pas d'accord avec Oto disant que c'est la faute du navigateur. Vous supposez essentiellement que quelque chose se produira instantanément alors qu'en réalité, il est asynchrone
Matt Fletcher
25

Cette solution maintiendra la position de défilement actuelle pendant que le défilement est désactivé, contrairement à certains qui font remonter l'utilisateur vers le haut.

Il est basé sur la réponse de galambalazs , mais avec un support pour les appareils tactiles, et refactorisé comme un seul objet avec le plugin jquery wrapper.

Démo ici.

Sur github ici.

/**
 * $.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
la source
Heureux que ce soit utile. NB J'ai édité avec un lien vers cela au format plugin jQuery .
Josh Harrison
Cela
@ user1672694, cela fonctionne ici dans Chrome. Quel est votre navigateur et sur quelle page de démonstration avez-vous trouvé le bug? Des erreurs JS dans la console?
Josh Harrison
Sur Chrome (38, Windows 7), je peux toujours faire défiler en cliquant et en maintenant le bouton du milieu enfoncé, puis en faisant glisser.
Sethi
1
Veuillez ignorer, j'ai trouvé que la reliure mousewheelfonctionnait à merveille
adamj
17

Je suis désolé de répondre à un ancien message mais je cherchais une solution et suis tombé sur cette question.

Il existe de nombreuses solutions pour que ce problème affiche toujours la barre de défilement, comme donner au conteneur une hauteur de 100% et un overflow-y: scroll style à .

Dans mon cas, je viens de créer un div avec une barre de défilement que j'affiche en ajoutant overflow: hiddenau corps:

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

La barre de défilement de l'élément doit avoir les styles suivants:

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

Cela montre une barre de défilement grise, j'espère que cela aidera les futurs visiteurs.

lisovaccaro
la source
8

Je cherchais une solution à ce problème mais je n'étais pas satisfait de l'une des solutions ci-dessus (au moment d'écrire cette réponse ), j'ai donc trouvé cette solution.

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
la source
J'ai trouvé que cela fonctionnait pour moi si j'augmentais overflow-y: scrollle .scrollDisabledstyle. Sinon, il y avait un petit saut car la barre de défilement se cachait à chaque fois. Bien sûr, cela ne fonctionne que pour moi car ma page est suffisamment longue pour avoir besoin d'une barre de défilement, même sur les plus grands écrans.
Andrew Miner
7

Selon l'article de galambalazs , j'ajouterais la prise en charge des appareils tactiles, ce qui nous permet de toucher mais pas de faire défiler vers le haut ou vers le bas:

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

function enable_scroll() {
   ...
   document.ontouchmove = function(e){ 
     return true; 
   }
}
jvalen
la source
3
Etes-vous sûr qu'il s'agit d'une réponse et pas seulement d'un commentaire d'une autre réponse?
IvanH
6

À partir de Chrome 56 et d'autres navigateurs modernes, vous devez ajouter passive:falseà l' addEventListenerappel pour que cela preventDefaultfonctionne. J'utilise donc ceci pour arrêter le défilement sur mobile:

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

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

Non, je n'irais pas avec la gestion des événements car:

  • tous les événements ne sont pas garantis pour atteindre le corps,

  • sélectionner du texte et se déplacer vers le bas fait défiler le document,

  • si à la phase d'événement, le détachement se passe mal, vous êtes condamné.

J'ai mordu par cela en faisant une action de copier-coller avec une zone de texte cachée et devinez quoi, la page défile chaque fois que je fais une copie car en interne je dois sélectionner la zone de texte avant d'appeler document.execCommand('copy') .

En tout cas c'est comme ça que je vais, notez le setTimeout():

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

Un élan clignote lorsque les barres de défilement disparaissent momentanément, mais c'est acceptable, je pense.

centurien
la source
4

En fonction de ce que vous souhaitez réaliser avec le défilement supprimé, vous pouvez simplement corriger l'élément dont vous souhaitez supprimer le défilement (au clic, ou tout autre déclencheur dont vous souhaitez désactiver temporairement le défilement)

Je cherchais une solution "temp no scroll" et pour mes besoins, cela l'a résolu

faire un cours

.fixed{
    position: fixed;
}

puis avec 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');
    };
});

J'ai trouvé que c'était une solution assez simple qui fonctionne bien sur tous les navigateurs, et qui permet également une utilisation simple sur des appareils portables (par exemple, iPhones, tablettes, etc.). Puisque l'élément est temporairement corrigé, il n'y a pas de défilement :)

REMARQUE! Selon l'emplacement de votre élément "contentContainer", vous devrez peut-être l'ajuster à partir de la gauche. Ce qui peut facilement être fait en ajoutant une valeur CSS à gauche à cet élément lorsque la classe fixe est active

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
la source
4

Une autre solution:

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

De cette façon, vous avez toujours une barre de défilement verticale, mais comme la plupart de mon contenu est plus long que la fenêtre d'affichage, cela me convient. Le contenu est centré avec un div séparé, mais sans redéfinir la marge dans le corps, mon contenu resterait à gauche.

Ce sont les deux fonctions que j'utilise pour afficher mon popup / 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);
}

Résultat: fond non déroulant et pas de repositionnement du contenu à cause de la barre de défilement gauche. Testé avec FF, Chrome et IE 10 actuels.

Marco
la source
Cela a fonctionné pour moi et le problème du défilement vers le haut après avoir utilisé la position: corrigé. Merci!
Annia Martinez
3

Que dis-tu de ça? (Si vous utilisez 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
la source
un peu nerveux, mais cela fonctionne pour IE 7 (le client l'utilise). d'autres solutions ne le font pas.
niki b
3

J'utilise showModalDialog , pour afficher la page secondaire comme boîte de dialogue modale.

pour masquer les barres de défilement de la fenêtre principale:

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

et lors de la fermeture de la boîte de dialogue modale, montrant les barres de défilement de la fenêtre principale:

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

pour accéder aux éléments de la fenêtre principale à partir de la boîte de dialogue:

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

juste pour quiconque recherche showModalDialog : (après la ligne 29 du code 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
la source
Cela a fonctionné pour moi dans React où jQuery est inexistant et où React n'a pas accès pour gérer l'état de la balise body.
Jon
3

L'annulation de l'événement comme dans la réponse acceptée est une méthode horrible à mon avis: /

Au lieu de cela, j'ai utilisé position: fixed; top: -scrollTop(); ci-dessous.

Démo: https://jsfiddle.net/w9w9hthy/5/

De mon projet popup 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": ""});
    }
}

Ce code prend en compte les problèmes de largeur, hauteur, barre de défilement et saut de page.

Problèmes possibles résolus avec le code ci-dessus:

  • largeur, lors du réglage de la position fixe, la largeur de l'élément html peut être inférieure à 100%
  • hauteur, comme ci-dessus
  • barre de défilement, lors de la définition de la position fixe, le contenu de la page n'a plus de barre de défilement même s'il y avait une barre de défilement avant d'entraîner un saut de page horizontal
  • saut de page, lorsque la position est fixée, le défilement de page n'est plus efficace, ce qui entraîne un saut de page vertical

Si quelqu'un a des améliorations au code de gel / dégel des pages ci-dessus, faites-le moi savoir afin que je puisse ajouter ces améliorations à mon projet.

hippocampe
la source
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
la source
1
C'est la meilleure solution ici.
jfunk
@jfunk d'accord, simple et concis, petit code, parfait. Merci
Florent Roques
2

J'ai le même problème, voici la façon dont je le gère.

/* 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;
}

j'espère que cette aide.

Robert
la source
1

S'appuyant sur la réponse de Cheyenne Forbes, et celle que j'ai trouvée ici via fcalderan: Désactivez simplement le défilement pour ne pas le cacher? et pour résoudre le problème d'Hallodom de la disparition de la barre de défilement

CSS:

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

JS:

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

Ce code vous fait sauter en haut de la page, mais je pense que le code de fcalderan a une solution de contournement.

Ergoter
la source
1

Je sais que c'est une vieille question, mais j'ai dû faire quelque chose de très similaire, et après un certain temps à chercher une réponse et à essayer différentes approches, j'ai fini par utiliser une solution très simple.

Mon problème était très similaire, presque identique, la seule différence est que je n'avais pas à afficher la barre de défilement - je devais juste m'assurer que sa largeur serait toujours utilisée, donc la largeur de la page ne changerait pas pendant l'affichage de ma superposition .

Lorsque je commence à faire glisser ma superposition sur l'écran, je fais:

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

et après avoir fait glisser ma superposition hors de l'écran, je fais:

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

IMPORTANT: cela fonctionne parfaitement car ma superposition est positionnée absolute, right: 0pxquand visible.

user2430829
la source
1

La méthode la plus simple est:

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

Pour l'annuler:

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

Facile à mettre en œuvre, mais le seul inconvénient est:

  • La page sautera un peu vers la gauche si elle est alignée au centre (horizontalement).

Cela est dû à la suppression de la barre de défilement et à l'élargissement de la fenêtre d'affichage.

Daan
la source
1
qui réinitialisera la position du défilement
Angel David Calderaro Pacciott
@AngelDavidCalderaroPacciott Non, la position de défilement restera la même hauteur / distance.
Daan
@Daan réinitialise la position de défilement sur Chrome
Tom
@Tom Je viens de le vérifier, il ne le fait qu'à certaines occasions (lorsque la hauteur du corps n'est pas relative à ses enfants). Veuillez essayer bodyde htmlremplacer par.
Daan
Je parie que vous n'avez pas vérifié votre solution dans Iphone car overflow:hiddencela ne fonctionne pas là
Shuvo
1

Voici ma solution pour arrêter le défilement (pas de jQuery). Je l'utilise pour désactiver le défilement lorsque le menu latéral apparaît.

<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>

J'ai mis 17px de padding-right pour compenser la disparition de la barre de défilement. Mais cela est également problématique, principalement pour les navigateurs mobiles. Résolu en obtenant la largeur de barre en fonction de cela .

Tous ensemble dans ce stylo.

Josep81
la source
1

C'est la solution la plus simple que j'ai eu jusqu'à présent. Et croyez-moi, j'ai essayé tous les autres et c'est le plus simple. Cela fonctionne très bien sur les appareils Windows , ce qui pousse la page de droite pour avoir de la place pour la barre de défilement du système et les appareils IOS qui ne nécessitent pas d'espace pour leurs barres de défilement dans les navigateurs. Donc, en utilisant cela, vous n'aurez pas besoin d'ajouter de rembourrage à droite pour que la page ne scintille pas lorsque vous masquez le débordement du corps ou du HTML avec CSS .

La solution est assez simple si vous y réfléchissez. L'idée est de donner à window.scrollTop () la même position exacte au moment où une popup est ouverte. Modifiez également cette position lorsque la fenêtre se redimensionne (car la position de défilement change une fois que cela se produit).

Alors c'est parti ...

Créons d'abord la variable qui vous fera savoir que la fenêtre contextuelle est ouverte et appelez-la stopWindowScroll . Si nous ne le faisons pas, vous obtiendrez une erreur d'une variable non définie sur votre page et définissez-la sur 0 - comme non active.

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

Permet maintenant de créer la fonction popup ouverte qui peut être n'importe quelle fonction de votre code qui déclenche la popup que vous utilisez en tant que plugin ou personnalisé. Dans ce cas, ce sera une simple fenêtre contextuelle personnalisée avec un simple document sur la fonction 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);
});

Donc, la prochaine chose que nous faisons est de créer la fonction close popup, qui, je le répète, peut être n'importe quelle fonction que vous avez déjà créée ou que vous utilisez dans un plugin. L'important est que nous avons besoin de ces 2 fonctions pour définir la variable stopWindowScroll sur 1 ou 0 pour savoir quand elle est ouverte ou fermée.

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

Permet ensuite de créer la fonction window.scroll afin que nous puissions empêcher le défilement une fois que stopWindowScroll mentionné ci-dessus est défini sur 1 - comme actif.

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

C'est ça. Aucun CSS requis pour que cela fonctionne, sauf vos propres styles pour la page. Cela a fonctionné comme un charme pour moi et j'espère que cela vous aide, vous et les autres.

Voici un exemple de travail sur JSFiddle:

Exemple JS Fiddle

Faites-moi savoir si cela a aidé. Cordialement.

Architecte
la source
1

Stockez la longueur du défilement dans une variable globale et restaurez-la si nécessaire!

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
la source
1

Ce code fonctionnera sur Chrome 56 et plus (la réponse d'origine ne fonctionne plus sur Chrome).

Utilisez DomUtils.enableScroll()pour activer le défilement.

Utilisez DomUtils.disableScroll()pour désactiver le défilement.

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
la source
1

Pour éviter le saut, c'est ce que j'ai utilisé

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

et dans mon css

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

J'ai trouvé cette réponse sur un autre site :

Désactiver le défilement:

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

Après avoir fermé le défilement de la version contextuelle:

$( ".popup" ).live({
    popupafterclose: function(event, ui) {
    $("body").unbind("touchmove");
}
});
pennstump
la source
Cela semble seulement arrêter le défilement tactile, mais le défilement de la souris, les touches fléchées, les touches de page haut et bas, etc. continueront de fonctionner. -1
markasoftware
Ces «événements» sont destinés au défilement tactile, remplacez simplement les événements dont vous avez besoin.
pennstump
1
cela semble également être utilisé dans une autre situation très spécifique. popupbeforeposition? À quoi cela est-il censé servir? Qu'est-ce que cela a à voir avec la désactivation temporaire du défilement? Rendez-le au moins pertinent à cette situation. Il semble que vous l'ayez copié directement à partir d'un site Web.
markasoftware
0

la solution de galambalazs est excellente! Cela a parfaitement fonctionné pour moi dans Chrome et Firefox. Et il peut également être étendu pour empêcher tout événement par défaut de la fenêtre du navigateur. Disons que vous faites une application sur la toile. Vous pouvez faire ceci:

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

Et puis sur votre application, disons que vous allez traiter vos propres événements, comme la souris, le clavier, les événements tactiles, etc. Vous pouvez désactiver les événements par défaut lorsque la souris pénètre dans le canevas et les réactiver lorsque la souris sort:

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

Vous pouvez même désactiver le menu clic droit avec ce hack:

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
la source
0

J'ai eu un problème d'animation similaire sur les écrans mobiles, mais pas sur les ordinateurs portables, lorsque j'essayais d'animer une div à l'aide de la commande animate de jquery. J'ai donc décidé d'utiliser une minuterie qui rétablissait la position de défilement de la fenêtre si fréquemment qu'à l'œil nu, le document semblait statique. Cette solution fonctionnait parfaitement sur un appareil mobile à petit écran comme Samsung Galaxy-2 ou iphone-5.

Logique principale de cette approche : Le minuteur pour définir la position de défilement de la fenêtre à la position de défilement d'origine doit être démarré avant la commande jquery animate, puis une fois l'animation terminée, nous devons effacer ce minuteur ( original scroll positionc'est la position juste avant le début de l'animation).

J'ai trouvé à ma grande surprise que le document semblait en fait statique pendant la durée de l'animation si l'intervalle de temporisation était 1 millisecond, ce que je visais.

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

UNE AUTRE SOLUTION qui a fonctionné : Sur la base de la réponse de Mohammad Anini sous ce post pour activer / désactiver le défilement, j'ai également constaté qu'une version modifiée du code comme ci-dessous fonctionnait.

//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
la source
0

Une solution simple qui a fonctionné pour moi (désactiver temporairement le défilement de la fenêtre).

Basé sur ce violon: http://jsfiddle.net/dh834zgw/1/

l'extrait de code suivant (à l'aide de jquery) désactivera le défilement de la fenêtre:

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

Et dans votre css:

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

Maintenant, lorsque vous supprimez le modal, n'oubliez pas de supprimer la classe noscroll sur la balise html:

$('html').toggleClass('noscroll');
lingue
la source