web-dev-qa-db-fra.com

Comment empêcher le défilement en arrière-plan lorsque Bootstrap 3 modal est ouvert sur les navigateurs mobiles?

Comment empêcher le défilement en arrière-plan lorsque Bootstrap 3 modal est ouvert sur les plates-formes mobiles? Sur les navigateurs de bureau, l’arrière-plan ne peut pas défiler et fonctionne comme il se doit.

Sur les navigateurs mobiles (Safari ios, Chrome ios, etc.), lorsqu'un modal est ouvert et que vous utilisez votre doigt pour le faire défiler, l'arrière-plan défile également de la même manière que le modal. Comment puis-je empêcher cela?

39
fat fantasma

Voir ici: https://github.com/twbs/bootstrap/issues/7501

Alors essayez:

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

V3.0.0. aurait dû résoudre ce problème. Utilisez-vous la dernière version? Si tel est le cas, posez un problème sur https://github.com/twbs/bootstrap/

36
Bass Jobsen

Essaye ça,

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

J'ai essayé la réponse acceptée qui empêchait le corps de défiler, mais qui posait le problème du défilement vers le haut. Cela devrait résoudre les deux problèmes. 

En remarque, il semble que débordement: masqué ne fonctionne pas sur le corps pour iOS Safari, car iOS Chrome fonctionne correctement.

var scrollPos = 0;

$('.modal')
    .on('show.bs.modal', function (){
        scrollPos = $('body').scrollTop();
        $('body').css({
            overflow: 'hidden',
            position: 'fixed',
            top : -scrollPos
        });
    })
    .on('hide.bs.modal', function (){
        $('body').css({
            overflow: '',
            position: '',
            top: ''
        }).scrollTop(scrollPos);
    });
18
Joe
$('.modal') 
.on('shown', function(){ 
  console.log('show'); 
  $('body').css({overflow: 'hidden'}); 
}) 
.on('hidden', function(){ 
  $('body').css({overflow: ''}); 
}); 

utiliser celui-ci 

9
Karthick Kumar

Aucun script nécessaire.

BS 3 définit une classe .modal-open sur le corps que vous pouvez utiliser pour définir les valeurs de position et de dépassement de capacité (définies avec LESS).

body {
    font-family:'Open Sans';
    margin:0;

    &.modal-open {
        position:fixed;
        overflow:hidden;

        .modal { 
            overflow: scroll;

            @media only screen and (min-resolution:150dpi) and (max-width: @screen-sm),
            only screen and (-webkit-min-device-pixel-ratio:1.5) {
                overflow: scroll; 
                -webkit-overflow-scrolling: touch; 
            }
        }
    }   
}
5
Martin

Si vous utilisez jQuery, vous pouvez le faire avec scrollTop

  1. Enregistrer la position de défilement vertical du corps;
  2. Désactiver le défilement sur le corps;
  3. Montrer modal;
  4. Proche modal;
  5. Réactiver le rouleau sur le corps;
  6. Définir la position de défilement enregistrée.

#modal {
    bottom: 0;
    position: fixed;
    overflow-y: scroll;
    overflow-x: hidden;
    top: 0;
    width: 100%;
}

$('.open-modal').click(function (e) {
    e.preventDefault();
    $('#modal').toggle();
    scrollTo = $('body').scrollTop();
    $('body').css("position", "fixed");
});

$('.close-modal').click(function (e) {
    e.preventDefault();
    $('#modal').toggle();
    $('body').css("position", "static");
    $('body').animate({scrollTop: scrollTo}, 0);
});

3
Tonijn

La solution choisie fonctionne, mais ils alignent également l'arrière-plan sur la position de défilement supérieure. J'ai étendu le code ci-dessus pour corriger ce "saut".

//Set 2 global variables
var scrollTopPosition = 0;
var lastKnownScrollTopPosition = 0;

//when the document loads
$(document).ready(function(){

  //this only runs on the right platform -- this step is not necessary, it should work on all platforms
  if( navigator.userAgent.match(/iPhone|iPad|iPod/i) ) {

    //There is some css below that applies here
    $('body').addClass('platform-ios');

    //As you scroll, record the scrolltop position in global variable
    $(window).scroll(function () {
      scrollTopPosition = $(document).scrollTop();
    });

    //when the modal displays, set the top of the (now fixed position) body to force it to the stay in the same place
    $('.modal').on('show.bs.modal', function () {

      //scroll position is position, but top is negative
      $('body').css('top', (scrollTopPosition * -1));

      //save this number for later
      lastKnownScrollTopPosition = scrollTopPosition;
    });

    //on modal hide
    $('.modal').on('hidden.bs.modal', function () {

      //force scroll the body back down to the right spot (you cannot just use scrollTopPosition, because it gets set to zero when the position of the body is changed by bootstrap
      $('body').scrollTop(lastKnownScrollTopPosition);
    });
  }
});

Le css est assez simple:

// You probably already have this, but just in case you don't
body.modal-open {
  overflow: hidden;
  width: 100%;
  height: 100%;
}
//only on this platform does it need to be fixed as well
body.platform-ios.modal-open {
  position: fixed;
}
3
Mark Pruce

Eu un problème avec cela aussi, iPhone + Safari où nécessaire d'ajouter:

position: fixed;

Comme mentionné ailleurs, cela a créé un problème de défilement vers le haut. La solution qui fonctionnait pour moi consistait à capturer la position au sommet à l'ouverture modale, puis à l'animer à cette position à la fermeture modale.

sur modal ouvert:

scrollTo = $('body').scrollTop();
$('body').css("position", "fixed");

à la fermeture modale

$('body').css("position", "static");
$('body').animate({scrollTop: scrollTo}, 0);
1
Ryan Charmley

Les réponses ci-dessus ne m'ont pas aidé, alors ce que j'ai fait était:

.modal {
  -webkit-overflow-scrolling: touch; 
}

Mon problème particulier était quand j'ai augmenté la taille modale après le chargement.

C'est un problème connu sur iOS, voir ici . Comme cela ne casse pas autre chose, la solution ci-dessus était suffisante pour mes besoins.

1
Mugur 'Bud' Chirica

J'ai pensé que vous pourriez oublier d'ajouter l'attribut data-toggle="modal" au lien ou au bouton qui déclenche l'événement contextuel modal. Tout d’abord, j’ai également le même problème mais, après avoir ajouté l’attribut ci-dessus, cela fonctionne bien pour moi.

1
Micheal

Cela pourrait être un peu comme battre un cheval mort ici .. mais ma solution actuellement mise en œuvre sur les modaux DIY par Vanilla JS:

En spectacle modal:

if (document.body.style.position !== 'fixed') {
    document.body.style.top = -window.scrollY + 'px';
    document.body.style.position = 'fixed';
}

Sur la peau modale:

document.body.style.position = '';
window.scrollTo(0, -parseInt(document.body.style.top, 10));
document.body.style.top = '';
1
Lucas

Hé les gars, alors je pense avoir trouvé une solution. Cela fonctionne pour moi sur iPhone et Android pour le moment. C'est un mélange de plusieurs heures de recherches, de lectures et de tests. Donc, si vous voyez des parties de votre code ici, le crédit vous revient, lol.

@media only screen and (max-device-width:768px){

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

body {  
overflow-x: hidden;
overflow-y: scroll !important;
}

La raison pour laquelle les médias sont spécifiques est sur un ordinateur de bureau lorsque je rencontrais des problèmes lorsque le modal ouvrait tout le contenu de la page passait du centre à la gauche. Ressemblait à de la merde. Donc, cela cible les appareils de la taille d’une tablette où il faudrait faire défiler. Il y a toujours un léger changement sur le mobile et la tablette, mais ce n'est vraiment pas beaucoup. Faites-moi savoir si cela fonctionne pour vous les gars. Espérons que cela met le clou dans le cercueil

0
JoeyD

Avec l'aimable autorisation de JDiApice qui a synthétisé et étendu le travail d'autres contributeurs sur le numéro de défilement modal iOS 8.x # 14839 :

@media only screen and (max-device-width:768px) {

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

body {
    overflow-x: hidden;
    overflow-y: scroll !important;
}

/* The reason the media specific is on there is 
   on a desktop i was having issues with when the modal would open 
   all content on the page would shift from centered to left. 
   Looked like crap. So this targets up to tablet size devices 
   where you would need to scroll. There is still a slight shift 
   on mobile and tablet but its really not much. */

Contrairement aux autres solutions que nous avons essayées, il ne fait pas défiler l'arrière-plan en haut après la fermeture de la fenêtre modale.

0
CAK2

Utiliser position:fixed a pour effet secondaire de faire défiler le corps vers le haut.

Si vous ne voulez pas que votre corps défile vers le haut, VEUILLEZ NOTER, utilisez position:fixed. Désactivez simplement le touchmove sur le corps si le modal est ouvert ..__ Remarque: le modal lui-même est toujours capable de défiler au toucher (s'il est plus grand que l'écran). 

CSS:

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

JS:

$('.modal').on('show.bs.modal', function (ev) { // prevent body from scrolling when modal opens
    $('body').bind('touchmove', function(e){
        if (!$(e.target).parents().hasClass( '.modal' )){ //only prevent touch move if it is not the modal
            e.preventDefault()
        }
    })
})
$('.modal').on('hide.bs.modal', function (e) { //unbind the touchmove restrictions from body when modal closes
    $('body').unbind('touchmove');
})

EDIT: .__ Remarque: pour les très petits modaux, vous devrez peut-être ajouter la ligne suivante à votre CSS:

.modal-dialog{
    height: 100%;
}
0
Kito

J'ouvre un modal après un modal et fait l'erreur de défilement modal, et ce css a résolu mon problème 

.modal {
    overflow-y: auto;
    padding-right: 15px;
}
0
sokphea chea

En complément à @Karthick Kumar answer from docs bootstrap

show est déclenché au début d'un événement

shown est déclenché à la fin d'une action

... donc ça devrait être:

$('.modal')
    .on('show.bs.modal', function (){
            $('body').css('overflow', 'hidden');
        })
    .on('hide.bs.modal', function (){
            // Also if you are using multiple modals (cascade) - additional check
            if ($('.modal.in').length == 1) {
                $('body').css('overflow', 'auto');
            }
        });
0
madzohan

J'ai trouvé une solution simple javascript/jquery qui utilise les événements modaux bootstrap.

Ma solution résout également le problème position:fixed dans lequel elle fait défiler la page d'arrière-plan jusqu'au dernier sommet au lieu de rester en place lorsque la fenêtre modale est ouverte/fermée. 

Voir détails ici

0
Truchainz

Je sais que cela a été répondu, mais aucune de ces solutions n'a fonctionné pour moi. Je devais adopter une approche différente. J'utilise PhoneGap et je compile mon code de manière native. J'ai donc dû déplacer l'arrière-plan vers le corps. J'espère que ça aidera quelqu'un d'autre. Ou s'il existe un moyen plus propre de le faire, n'hésitez pas à commenter ...

$(document).on('shown.bs.modal', '.modal', function (e) {

    $("#" + e.target.id).find(".modal-backdrop").css("z-index", $("#" + e.target.id).css("z-index")).insertBefore("#" + e.target.id);

});
0
Paul