web-dev-qa-db-fra.com

Empêcher le corps de défiler lorsqu'un modal est ouvert

Je veux que mon corps arrête de faire défiler le texte lorsque j'utilise la molette lorsque le modal (de http://Twitter.github.com/bootstrap ) est ouvert.

J'ai essayé d'appeler le morceau de javascript ci-dessous quand le modal est ouvert mais sans succès

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

AND

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

Veuillez noter que notre site Web a cessé de prendre en charge IE6, mais que IE7 + doit être compatible.

292
xorinzor

La variable modal de Bootstrap ajoute automatiquement la classe modal-open au corps lorsqu'une boîte de dialogue modale est affichée et la supprime lorsque la boîte de dialogue est masquée. Vous pouvez donc ajouter ce qui suit à votre CSS:

body.modal-open {
    overflow: hidden;
}

Vous pourriez faire valoir que le code ci-dessus appartient à la base de code CSS Bootstrap, mais il s'agit d'une solution facile pour l'ajouter à votre site.

Mise à jour du 8 février 2013
Cela ne fonctionne plus dans Twitter Boostrap v. 2.3.0 - ils n’ajoutent plus la classe modal-open au corps.

Une solution de contournement consisterait à ajouter la classe au corps lorsque le modal est sur le point d'être affiché et à la supprimer lorsque le modal est fermé:

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

Mise à jour du 11 mars 2013 On dirait que la classe modal-open va revenir dans Bootstrap 3.0, explicitement dans le but d'empêcher le défilement: 

Réintroduit .modal-open sur le corps (afin que nous puissions nuancer le parchemin là-bas)

Voir ceci: https://github.com/Twitter/bootstrap/pull/6342 - consultez la section Modal.

418
MartinHN

La réponse acceptée ne fonctionne pas sur mobile (iOS 7 avec Safari 7, au moins) et je ne veux pas que JavaScript de MOAR s'exécute sur mon site lorsque CSS le fera.

Ce CSS empêchera la page d’arrière-plan de défiler sous le modal:

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

Cependant, il a également un léger effet secondaire de faire défiler essentiellement vers le haut. position:absolute résout ce problème, mais réintroduit la possibilité de faire défiler sur mobile.

Si vous connaissez votre fenêtre d'affichage ( mon plugin permettant d'ajouter une fenêtre d'affichage à <body> ), vous pouvez simplement ajouter une bascule CSS pour la variable 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; 
}

J'ajoute également ceci pour empêcher la page sous-jacente de sauter gauche/droite lors de l'affichage/du masquage des modaux.

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

cette réponse est un x-post.

103
Brad

Il suffit de masquer le débordement du corps pour que le corps ne défile pas. Lorsque vous masquez le modal, rétablissez-le en mode automatique. 

Voici le code:

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

Vous pouvez essayer de définir la taille du corps sur la taille de la fenêtre avec dépassement: masqué lorsque modal est ouvert

20
charlietfl

Attention: L'option ci-dessous n'est pas pertinente pour Bootstrap v3.0.x car le défilement dans ces versions a été explicitement limité au modal lui-même. Si vous désactivez les événements de roue, vous pouvez empêcher par inadvertance l'affichage de certains utilisateurs. contenu dans les modaux dont les hauteurs sont supérieures à la hauteur de la fenêtre.


Encore une autre option: les événements sur roues

L'événement scroll n'est pas annulable. Cependant, il est possible d'annuler les événements mousewheel et wheel . Le gros inconvénient est que tous les navigateurs traditionnels ne les prennent pas en charge, Mozilla n’ayant que récemment ajouté la prise en charge de ce dernier dans Gecko 17.0. Je ne connais pas la diffusion complète, mais IE6 + et Chrome les prennent en charge.

Voici comment les exploiter:

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

JSFiddle

17
merv

Vous devez aller au-delà de la réponse de @ charlietfl et rendre compte des barres de défilement, sinon vous risquez de voir un document redistribuer.

Ouverture du modal:

  1. Notez la largeur body
  2. Définissez body overflow sur hidden
  3. Définir explicitement la largeur du corps à ce qu’elle était à l’étape 1.

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

Fermeture du modal:

  1. Définissez body overflow sur auto
  2. Définissez body width sur auto

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

Inspiré par: http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php

14
jpap

Essaye celui-là:

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

cela a fonctionné pour moi. (supporte IE8)

9
fatCop
/* =============================
 * 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(); });
});
8
jparkerweb

Impossible de le faire fonctionner sur Chrome en changeant simplement CSS, car je ne voulais pas que la page revienne au début. Cela a bien fonctionné:

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

Je ne suis pas sûr de ce code, mais ça vaut le coup.

Dans jQuery:

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

Comme je l'ai déjà dit, je ne suis pas sûr à 100% mais essayez quand même.

6
Anish Gupta

L'ajout de la classe 'is-modal-open' ou la modification du style d'une balise body avec javascript est correct et fonctionne comme prévu. Mais le problème auquel nous allons faire face est lorsque le corps devient débordé: caché, il sautera au sommet (scrollTop deviendra 0). Cela deviendra un problème d'utilisabilité plus tard. 

En guise de solution à ce problème, au lieu de modifier le débordement de balise body: masqué, changez-le en balise HTML.

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

Pour Bootstrap , vous pouvez essayer ceci (en travaillant sur Firefox, Chrome et Microsoft Edge):

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

J'espère que cela t'aides...

3
Murat Yıldız

La meilleure solution est la solution css body{overflow:hidden} utilisée par la plupart de ces réponses. Certaines réponses offrent une solution qui empêche également le "saut" causé par la barre de défilement qui disparaît; Cependant, aucun n'était trop élégant. J'ai donc écrit ces deux fonctions et elles semblent fonctionner assez 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');
}

Découvrez this jsFiddle pour le voir en cours d’utilisation.

3
Stephen M. Harris

Vous pouvez utiliser la logique suivante, je l'ai testée et cela fonctionne (même dans 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>
3
myriacl

J'avais une barre latérale générée par la case à cocher hack . Mais l'idée principale est de sauvegarder le document scrollTop et de ne pas le changer pendant le défilement de la fenêtre.

Je n'ai simplement pas aimé que la page saute quand le corps devient 'débordement: caché'.

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

});

Malheureusement, aucune des réponses ci-dessus n'a résolu mes problèmes.

Dans ma situation, la page Web a initialement une barre de défilement. Chaque fois que je clique sur le modal, la barre de défilement ne disparaît pas et l'en-tête se déplace légèrement vers la droite.

Ensuite, j'ai essayé d'ajouter .modal-open{overflow:auto;} (recommandé par la plupart des gens). Il a en effet corrigé les problèmes: la barre de défilement apparaît après l’ouverture du modal. Cependant, un autre effet secondaire apparaît, à savoir que "l'arrière-plan situé sous l'en-tête se déplace légèrement vers la gauche, avec une autre longue barre derrière le modal"

 Long bar behind modal

Heureusement, après avoir ajouté {padding-right: 0 !important;}, tout est parfaitement corrigé. L'en-tête et le fond du corps n'ont pas bougé et le modal conserve toujours la barre de défilement.

 Fixed image

J'espère que cela pourra aider ceux qui sont encore aux prises avec ce problème. Bonne chance!

2
Bocard Wang

À partir de novembre 2017, Chrome a introduit une nouvelle propriété css

overscroll-behavior: contain;

qui résout ce problème bien que, au moment de l’écriture, ne supporte que plusieurs navigateurs.

voir les liens ci-dessous pour plus de détails et le support du navigateur 

2
user1095118

Beaucoup suggèrent "débordement: caché" sur le corps, ce qui ne fonctionnera pas (pas du moins dans mon cas), car le site Web défilera jusqu'au sommet.

C'est la solution qui fonctionne pour moi (à la fois sur les téléphones mobiles et les ordinateurs), en utilisant 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');
    });

Cela fera fonctionner le défilement du modal et empêchera le site Web de défiler en même temps.

2
Danie

D'après ce violon: http://jsfiddle.net/dh834zgw/1/

le fragment de code suivant (utilisant 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');
2
ling

Si modal sont 100% hauteur/largeur, "mouseenter/leave" fonctionnera pour activer/désactiver facilement le défilement Cela a vraiment fonctionné pour moi:

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
Mats

Ma solution pour Bootstrap 3:

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

car pour moi le seul overflow: hidden de la classe body.modal-open n'empêchait pas la page de se déplacer vers la gauche en raison du margin-right: 15px d'origine.

1
pierrea

La plupart des pièces sont ici, mais je ne vois pas de réponse qui rassemble tout.

Le problème est triple.

(1) empêcher le défilement de la page sous-jacente

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

(2) et retirez la barre de défilement

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

(3) nettoyer lorsque le modal est licencié

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

Si le modal n'est pas en plein écran, appliquez les liaisons .modal à une superposition en plein écran.

1
evoskuil

Je ne suis pas sûr à 100% que cela fonctionne avec Bootstrap, mais cela vaut la peine d'essayer - cela a fonctionné avec Remodal.js qui peut être trouvé sur github: http://vodkabears.github.io/remodal/ et cela ferait sens pour que les méthodes soient assez similaires.

Pour empêcher la page de sauter en haut et empêcher le décalage correct du contenu, ajoutez une classe à la body lorsque le modal est déclenché et définissez les règles CSS suivantes:

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

C'est le position:static et le height:auto qui se combinent pour empêcher le passage du contenu à droite. Le overflow-y:hidden; arrête le défilement de la page derrière le modal.

1
AdamJB

Je viens de le faire de cette façon ...

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

Mais lorsque la roulette disparut, elle déplaça tout droit 20px, alors j’ai ajouté 

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

juste après.

Travaille pour moi.

1
Cliff

a travaillé pour moi

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

Cacher le débordement et fixer la position fait l'affaire, mais avec ma conception fluide, il serait résolu au-delà de la largeur du navigateur, donc une largeur: 100% corrigée.

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

J'utilise cette fonction Vanilla js pour ajouter la classe "modal-open" au corps. (Basé sur la réponse de smhmic)

function freezeScroll(show, new_width)
{
    var innerWidth = window.innerWidth,
        clientWidth = document.documentElement.clientWidth,
        new_margin = ((show) ? (new_width + innerWidth - clientWidth) : new_width) + "px";

    document.body.style.marginRight = new_margin;
    document.body.className = (show) ? "modal-open" : "";
};
0
Omer M.

C'est la meilleure solution pour moi: 

Css:

.modal {
     overflow-y: auto !important;
}

Et Js:

modalShown = function () {
    $('body').css('overflow', 'hidden');
},

modalHidden = function () {
    $('body').css('overflow', 'auto');
}
0
ibrahimyilmaz

Utilisez body-scroll-lock

Très léger, très soigné et populaire

0
adardesign

Essayez ce code:

$('.entry_details').dialog({
    width:800,
    height:500,
    draggable: true,
    title: entry.short_description,
    closeText: "Zamknij",
    open: function(){
        //    blokowanie scrolla dla body
        var body_scroll = $(window).scrollTop();
        $(window).on('scroll', function(){
            $(document).scrollTop(body_scroll);
        });
    },
    close: function(){
        $(window).off('scroll');
    }
}); 
0
Jarosław Osmólski
   $('.modal').on('shown.bs.modal', function (e) {
      $('body').css('overflow-y', 'hidden');
   });
   $('.modal').on('hidden.bs.modal', function (e) {
      $('body').css('overflow-y', '');
   });
0
Fernando Siqueira

Une petite note pour ceux de SharePoint 2013. Le corps a déjà overflow: hidden. Ce que vous cherchez, c’est de définir overflow: hidden sur un élément div avec id s4-workspace, par exemple.

var body = document.getElementById('s4-workspace');
body.className = body.className+" modal-open";
0
Kristian

Ce qui précède se produit lorsque vous utilisez un modal dans un autre modal. Lorsque j'ouvre un modal dans un autre modal, la fermeture de ce dernier supprime la classe modal-open de la body. La solution du problème dépend de la façon dont vous fermez ce dernier modal.

Si vous fermez le modal avec HTML comme,

<button type="button" class="btn" data-dismiss="modal">Close</button>

Ensuite, vous devez ajouter un auditeur comme celui-ci,

$(modalSelector).on("hidden.bs.modal", function (event) {
    event.stopPropagation();
    $("body").addClass("modal-open");
    return false;
});

Si vous fermez le modal à l'aide de javascript comme,

$(modalSelector).modal("hide");

Ensuite, vous devez exécuter la commande un peu après, comme ceci,

setInterval(function(){$("body").addClass("modal-open");}, 300);
0
George Siggouroglou

Pour ceux qui se demandent comment obtenir l'événement de défilement pour le modal bootstrap 3:

$(".modal").scroll(function() {
    console.log("scrolling!);
});
0
Arie

Ce qui a finalement résolu le problème pour moi, c’est Verrou de défilement du corps .

Les autres solutions ne désactivent pas le défilement sur iOS.

0
app developer 27

Cela a fonctionné pour moi:

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

Vous devez ajouter overflow: hidden en HTML pour une meilleure performance multiplateforme.

J'utiliserais

html.no-scroll {
    overflow: hidden;
}
0
Afonso

Puisque pour moi ce problème présenté principalement sur iOS, je fournis le code pour résoudre ce problème uniquement sur 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;
    });
  }
0
LowFieldTheory

Pourquoi ne pas le faire comme Bulma le fait? Lorsque modal est actif, ajoutez au code HTML leur classe .is-clipped qui est un débordement: hidden! Important;

Edit: Okey, Bulma a ce bogue, vous devez donc ajouter aussi d'autres choses comme

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