Multiple modals overlay

2019-01-01 09:42发布

问题:

I need that the overlay shows above the first modal, not in the back.

\"Modal

$(\'#openBtn\').click(function(){
	$(\'#myModal\').modal({show:true})
});
<a data-toggle=\"modal\" href=\"#myModal\" class=\"btn btn-primary\">Launch modal</a>

<div class=\"modal\" id=\"myModal\">
	<div class=\"modal-dialog\">
      <div class=\"modal-content\">
        <div class=\"modal-header\">
          <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">×</button>
          <h4 class=\"modal-title\">Modal title</h4>
        </div><div class=\"container\"></div>
        <div class=\"modal-body\">
          Content for the dialog / modal goes here.
          <br>
          <br>
          <br>
          <br>
          <br>
          <a data-toggle=\"modal\" href=\"#myModal2\" class=\"btn btn-primary\">Launch modal</a>
        </div>
        <div class=\"modal-footer\">
          <a href=\"#\" data-dismiss=\"modal\" class=\"btn\">Close</a>
          <a href=\"#\" class=\"btn btn-primary\">Save changes</a>
        </div>
      </div>
    </div>
</div>
<div class=\"modal\" id=\"myModal2\" data-backdrop=\"static\">
	<div class=\"modal-dialog\">
      <div class=\"modal-content\">
        <div class=\"modal-header\">
          <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">×</button>
          <h4 class=\"modal-title\">Second Modal title</h4>
        </div><div class=\"container\"></div>
        <div class=\"modal-body\">
          Content for the dialog / modal goes here.
        </div>
        <div class=\"modal-footer\">
          <a href=\"#\" data-dismiss=\"modal\" class=\"btn\">Close</a>
          <a href=\"#\" class=\"btn btn-primary\">Save changes</a>
        </div>
      </div>
    </div>
</div>


<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css\" />
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js\"></script>
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/js/bootstrap.min.js\"></script>

I tried to change the z-index of .modal-backdrop, but it becomes a mess.

In some cases I have more than two modals on the same page.

回答1:

After seeing many fixes for this, and none of them were exactly what I needed I\'ve came up with a even shorter solution that is inspired by @YermoLamers & @Ketwaroo.

Backdrop z-index fix
This solution uses a setTimeout because the .modal-backdrop isn\'t created when the event show.bs.modal is triggered.

$(document).on(\'show.bs.modal\', \'.modal\', function () {
    var zIndex = 1040 + (10 * $(\'.modal:visible\').length);
    $(this).css(\'z-index\', zIndex);
    setTimeout(function() {
        $(\'.modal-backdrop\').not(\'.modal-stack\').css(\'z-index\', zIndex - 1).addClass(\'modal-stack\');
    }, 0);
});
  • This works for every .modal created on the page (even dynamic modals)
  • The backdrop instantly overlays the previous modal

Example jsfiddle

If you don\'t like the hardcoded z-index for any reason you can calculate the highest z-index on the page like this:

var zIndex = Math.max.apply(null, Array.prototype.map.call(document.querySelectorAll(\'*\'), function(el) {
  return +el.style.zIndex;
})) + 10;

Scrollbar fix
If you have a modal on your page that exceeds the browser height, then you can\'t scroll in it when closing an second modal. To fix this add:

$(document).on(\'hidden.bs.modal\', \'.modal\', function () {
    $(\'.modal:visible\').length && $(document.body).addClass(\'modal-open\');
});

Versions
This solution is tested with bootstrap 3.1.0 - 3.3.5



回答2:

I realize an answer has been accepted, but I strongly suggest not hacking bootstrap to fix this.

You can pretty easily achieve the same effect by hooking the shown.bs.modal and hidden.bs.modal event handlers and adjusting the z-index there.

Here\'s a working example

A bit more info is available here.

This solution works automatically with arbitrarily deeply stacks modals.

The script source code:

$(document).ready(function() {

    $(\'.modal\').on(\'hidden.bs.modal\', function(event) {
        $(this).removeClass( \'fv-modal-stack\' );
        $(\'body\').data( \'fv_open_modals\', $(\'body\').data( \'fv_open_modals\' ) - 1 );
    });

    $(\'.modal\').on(\'shown.bs.modal\', function (event) {
        // keep track of the number of open modals
        if ( typeof( $(\'body\').data( \'fv_open_modals\' ) ) == \'undefined\' ) {
            $(\'body\').data( \'fv_open_modals\', 0 );
        }

        // if the z-index of this modal has been set, ignore.
        if ($(this).hasClass(\'fv-modal-stack\')) {
            return;
        }

        $(this).addClass(\'fv-modal-stack\');
        $(\'body\').data(\'fv_open_modals\', $(\'body\').data(\'fv_open_modals\' ) + 1 );
        $(this).css(\'z-index\', 1040 + (10 * $(\'body\').data(\'fv_open_modals\' )));
        $(\'.modal-backdrop\').not(\'.fv-modal-stack\').css(\'z-index\', 1039 + (10 * $(\'body\').data(\'fv_open_modals\')));
        $(\'.modal-backdrop\').not(\'fv-modal-stack\').addClass(\'fv-modal-stack\'); 

    });        
});


回答3:

Something shorter version based off Yermo Lamers\' suggestion, this seems to work alright. Even with basic animations like fade in/out and even crazy batman newspaper rotate. http://jsfiddle.net/ketwaroo/mXy3E/

$(\'.modal\').on(\'show.bs.modal\', function(event) {
    var idx = $(\'.modal:visible\').length;
    $(this).css(\'z-index\', 1040 + (10 * idx));
});
$(\'.modal\').on(\'shown.bs.modal\', function(event) {
    var idx = ($(\'.modal:visible\').length) -1; // raise backdrop after animation.
    $(\'.modal-backdrop\').not(\'.stacked\').css(\'z-index\', 1039 + (10 * idx));
    $(\'.modal-backdrop\').not(\'.stacked\').addClass(\'stacked\');
});


回答4:

Combining A1rPun\'s answer with the suggestion by StriplingWarrior, I came up with this:

$(document).on({
    \'show.bs.modal\': function () {
        var zIndex = 1040 + (10 * $(\'.modal:visible\').length);
        $(this).css(\'z-index\', zIndex);
        setTimeout(function() {
            $(\'.modal-backdrop\').not(\'.modal-stack\').css(\'z-index\', zIndex - 1).addClass(\'modal-stack\');
        }, 0);
    },
    \'hidden.bs.modal\': function() {
        if ($(\'.modal:visible\').length > 0) {
            // restore the modal-open class to the body element, so that scrolling works
            // properly after de-stacking a modal.
            setTimeout(function() {
                $(document.body).addClass(\'modal-open\');
            }, 0);
        }
    }
}, \'.modal\');

Works even for dynamic modals added after the fact, and removes the second-scrollbar issue. The most notable thing that I found this useful for was integrating forms inside modals with validation feedback from Bootbox alerts, since those use dynamic modals and thus require you to bind the event to document rather than to .modal, since that only attaches it to existing modals.

Fiddle here.



回答5:

I created a Bootstrap plugin that incorporates a lot of the ideas posted here.

Demo on Bootply: http://www.bootply.com/cObcYInvpq

Github: https://github.com/jhaygt/bootstrap-multimodal

It also addresses the issue with successive modals causing the backdrop to become darker and darker. This ensures that only one backdrop is visible at any given time:

if(modalIndex > 0)
    $(\'.modal-backdrop\').not(\':first\').addClass(\'hidden\');

The z-index of the visible backdrop is updated on both the show.bs.modal and hidden.bs.modal events:

$(\'.modal-backdrop:first\').css(\'z-index\', MultiModal.BASE_ZINDEX + (modalIndex * 20));


回答6:

When solving Stacking modals scrolls the main page when one is closed i found that newer versions of Bootstrap (at least since version 3.0.3) do not require any additional code to stack modals.

You can add more than one modal (of course having a different ID) to your page. The only issue found when opening more than one modal will be that closing one remove the modal-open class for the body selector.

You can use the following Javascript code to re-add the modal-open :

$(\'.modal\').on(\'hidden.bs.modal\', function (e) {
    if($(\'.modal\').hasClass(\'in\')) {
    $(\'body\').addClass(\'modal-open\');
    }    
});

In the case that do not need the backdrop effect for the stacked modal you can set data-backdrop=\"false\".

Version 3.1.1. fixed Fix modal backdrop overlaying the modal\'s scrollbar, but the above solution seems also to work with earlier versions.



回答7:

Finally solved. I tested it in many ways and works fine.

Here is the solution for anyone that have the same problem: Change the Modal.prototype.show function (at bootstrap.js or modal.js)

FROM:

if (transition) {
   that.$element[0].offsetWidth // force reflow
}   

that.$element
   .addClass(\'in\')
   .attr(\'aria-hidden\', false)

that.enforceFocus()

TO:

if (transition) {
    that.$element[0].offsetWidth // force reflow
}

that.$backdrop
   .css(\"z-index\", (1030 + (10 * $(\".modal.fade.in\").length)))

that.$element
   .css(\"z-index\", (1040 + (10 * $(\".modal.fade.in\").length)))
   .addClass(\'in\')
   .attr(\'aria-hidden\', false)

that.enforceFocus()

It\'s the best way that i found: check how many modals are opened and change the z-index of the modal and the backdrop to a higher value.



回答8:

Try adding the following to your JS on bootply

$(\'#myModal2\').on(\'show.bs.modal\', function () {  
$(\'#myModal\').css(\'z-index\', 1030); })

$(\'#myModal2\').on(\'hidden.bs.modal\', function () {  
$(\'#myModal\').css(\'z-index\', 1040); })

Explanation:

After playing around with the attributes(using Chrome\'s dev tool), I have realized that any z-index value below 1031 will put things behind the backdrop.

So by using bootstrap\'s modal event handles I set the z-index to 1030. If #myModal2 is shown and set the z-index back to 1040 if #myModal2 is hidden.

Demo



回答9:

Everytime you run sys.showModal function increment z-index and set it to your new modal.

function system() {

    this.modalIndex = 2000;

    this.showModal = function (selector) {
        this.modalIndex++;

        $(selector).modal({
            backdrop: \'static\',
            keyboard: true
        });
        $(selector).modal(\'show\');
        $(selector).css(\'z-index\', this.modalIndex );       
    }

}

var sys = new system();

sys.showModal(\'#myModal1\');
sys.showModal(\'#myModal2\');


回答10:

Each modal should be given a different id and each link should be targeted to a different modal id. So it should be something like that:

<a href=\"#myModal\" data-toggle=\"modal\">
...
<div id=\"myModal\" class=\"modal hide fade\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"myModalLabel\" aria-hidden=\"true\"></div>
...
<a href=\"#myModal2\" data-toggle=\"modal\">
...
<div id=\"myModal2\" class=\"modal hide fade\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"myModalLabel\" aria-hidden=\"true\"></div>
...


回答11:

The solution to this for me was to NOT use the \"fade\" class on my modal divs.



回答12:

EDIT: Bootstrap 3.3.4 has solved this problem (and other modal issues) so if you can update your bootstrap CSS and JS that would be the best solution. If you can\'t update the solution below will still work and essentially does the same thing as bootstrap 3.3.4 (recalculate and apply padding).

As Bass Jobsen pointed out, newer versions of Bootstrap have the z-index solved. The modal-open class and padding-right were still problems for me but this scripts inspired by Yermo Lamers solution solves it. Just drop it in your JS file and enjoy.

$(document).on(\'hide.bs.modal\', \'.modal\', function (event) {
    var padding_right = 0;
    $.each($(\'.modal\'), function(){
        if($(this).hasClass(\'in\') && $(this).modal().data(\'bs.modal\').scrollbarWidth > padding_right) {
            padding_right = $(this).modal().data(\'bs.modal\').scrollbarWidth
        }
    });
    $(\'body\').data(\'padding_right\', padding_right + \'px\');
});

$(document).on(\'hidden.bs.modal\', \'.modal\', function (event) {
    $(\'body\').data(\'open_modals\', $(\'body\').data(\'open_modals\') - 1);
    if($(\'body\').data(\'open_modals\') > 0) {
        $(\'body\').addClass(\'modal-open\');
        $(\'body\').css(\'padding-right\', $(\'body\').data(\'padding_right\'));
    }
});

$(document).on(\'shown.bs.modal\', \'.modal\', function (event) {
    if (typeof($(\'body\').data(\'open_modals\')) == \'undefined\') {
        $(\'body\').data(\'open_modals\', 0);
    }
    $(\'body\').data(\'open_modals\', $(\'body\').data(\'open_modals\') + 1);
    $(\'body\').css(\'padding-right\', (parseInt($(\'body\').css(\'padding-right\')) / $(\'body\').data(\'open_modals\') + \'px\'));
});


回答13:

work for open/close multi modals

jQuery(function()
{
    jQuery(document).on(\'show.bs.modal\', \'.modal\', function()
    {
        var maxZ = parseInt(jQuery(\'.modal-backdrop\').css(\'z-index\')) || 1040;

        jQuery(\'.modal:visible\').each(function()
        {
            maxZ = Math.max(parseInt(jQuery(this).css(\'z-index\')), maxZ);
        });

        jQuery(\'.modal-backdrop\').css(\'z-index\', maxZ);
        jQuery(this).css(\"z-index\", maxZ + 1);
        jQuery(\'.modal-dialog\', this).css(\"z-index\", maxZ + 2);
    });

    jQuery(document).on(\'hidden.bs.modal\', \'.modal\', function () 
    {
        if (jQuery(\'.modal:visible\').length)
        {
            jQuery(document.body).addClass(\'modal-open\');

           var maxZ = 1040;

           jQuery(\'.modal:visible\').each(function()
           {
               maxZ = Math.max(parseInt(jQuery(this).css(\'z-index\')), maxZ);
           });

           jQuery(\'.modal-backdrop\').css(\'z-index\', maxZ-1);
       }
    });
});

Demo

https://www.bootply.com/cObcYInvpq#



回答14:

Here is some CSS using nth-of-type selectors that seems to work:

.modal:nth-of-type(even) {
    z-index: 1042 !important;
}
.modal-backdrop.in:nth-of-type(even) {
    z-index: 1041 !important;
}

Bootply: http://bootply.com/86973



回答15:

I had a similar scenario, and after a little bit of R&D I found a solution. Although I\'m not great in JS still I have managed to write down a small query.

http://jsfiddle.net/Sherbrow/ThLYb/

<div class=\"ingredient-item\" data-toggle=\"modal\" data-target=\"#myModal\">test1 <p>trerefefef</p></div>
<div class=\"ingredient-item\" data-toggle=\"modal\" data-target=\"#myModal\">tst2 <p>Lorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem IpsumLorem Ipsum</p></div>
<div class=\"ingredient-item\" data-toggle=\"modal\" data-target=\"#myModal\">test3 <p>afsasfafafsa</p></div>

<!-- Modal -->
<div class=\"modal fade\" id=\"myModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"myModalLabel\" aria-hidden=\"true\">
  <div class=\"modal-dialog\">
    <div class=\"modal-content\">
      <div class=\"modal-header\">
        <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">&times;</button>
        <h4 class=\"modal-title\" id=\"myModalLabel\">Modal title</h4>
      </div>
      <div class=\"modal-body\">
        ...
      </div>
      <div class=\"modal-footer\">
        <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">Close</button>
        <button type=\"button\" class=\"btn btn-primary\">Save changes</button>
      </div>
    </div>
  </div>
</div>





$(\'.ingredient-item\').on(\'click\', function(e){

   e.preventDefault();

    var content = $(this).find(\'p\').text();

    $(\'.modal-body\').html(content);

});


回答16:

Add global variable in modal.js

var modalBGIndex = 1040; // modal backdrop background
var modalConIndex = 1042; // modal container data 

// show function inside add variable - Modal.prototype.backdrop

var e    = $.Event(\'show.bs.modal\', { relatedTarget: _relatedTarget })

modalConIndex = modalConIndex + 2; // add this line inside \"Modal.prototype.show\"

that.$element
    .show()
    .scrollTop(0)
that.$element.css(\'z-index\',modalConIndex) // add this line after show modal 

if (this.isShown && this.options.backdrop) {
      var doAnimate = $.support.transition && animate

      modalBGIndex = modalBGIndex + 2; // add this line increase modal background index 2+

this.$backdrop.addClass(\'in\')
this.$backdrop.css(\'z-index\',modalBGIndex) // add this line after backdrop addclass


回答17:

Try this http://nakupanda.github.io/bootstrap3-dialog/#opening-multiple-dialogs

It should easily solve your problem.



回答18:

The other solutions did not work for me out of the box. I think perhaps because I am using a more recent version of Bootstrap (3.3.2).... the overlay was appearing on top of the modal dialog.

I refactored the code a bit and commented out the part that was adjusting the modal-backdrop. This fixed the issue.

    var $body = $(\'body\');
    var OPEN_MODALS_COUNT = \'fv_open_modals\';
    var Z_ADJUSTED = \'fv-modal-stack\';
    var defaultBootstrapModalZindex = 1040;

    // keep track of the number of open modals                   
    if ($body.data(OPEN_MODALS_COUNT) === undefined) {
        $body.data(OPEN_MODALS_COUNT, 0);
    }

    $body.on(\'show.bs.modal\', \'.modal\', function (event)
    {
        if (!$(this).hasClass(Z_ADJUSTED))  // only if z-index not already set
        {
            // Increment count & mark as being adjusted
            $body.data(OPEN_MODALS_COUNT, $body.data(OPEN_MODALS_COUNT) + 1);
            $(this).addClass(Z_ADJUSTED);

            // Set Z-Index
            $(this).css(\'z-index\', defaultBootstrapModalZindex + (1 * $body.data(OPEN_MODALS_COUNT)));

            //// BackDrop z-index   (Doesn\'t seem to be necessary with Bootstrap 3.3.2 ...)
            //$(\'.modal-backdrop\').not( \'.\' + Z_ADJUSTED )
            //        .css(\'z-index\', 1039 + (10 * $body.data(OPEN_MODALS_COUNT)))
            //        .addClass(Z_ADJUSTED);
        }
    });
    $body.on(\'hidden.bs.modal\', \'.modal\', function (event)
    {
        // Decrement count & remove adjusted class
        $body.data(OPEN_MODALS_COUNT, $body.data(OPEN_MODALS_COUNT) - 1);
        $(this).removeClass(Z_ADJUSTED);
        // Fix issue with scrollbar being shown when any modal is hidden
        if($body.data(OPEN_MODALS_COUNT) > 0)
            $body.addClass(\'modal-open\');
    });

As a side note, if you want to use this in AngularJs, just put the code inside of your module\'s .run() method.



回答19:

Unfortunately I do not have the reputation to comment, but it should be noted that the accepted solution with the hardcoded baseline of a 1040 z-index seems to be superior to the zIndex calculation that tries to find the maximum zIndex being rendered on the page.

It appears that certain extensions/plugins rely on top level DOM content which makes the .Max calculation such an obscenely large number, that it can\'t increment the zIndex any further. This results in a modal where the overlay appears over the modal incorrectly (if you use Firebug/Google Inspector tools you\'ll see a zIndex on the order of 2^n - 1)

I haven\'t been able to isolate what the specific reason the various forms of Math.Max for z-Index leads to this scenario, but it can happen, and it will appear unique to a few users. (My general tests on browserstack had this code working perfectly).

Hope this helps someone.



回答20:

In my case the problem was caused by a browser extension that includes the bootstrap.js files where the show event handled twice and two modal-backdrop divs are added, but when closing the modal only one of them is removed.

Found that by adding a subtree modification breakpoint to the body element in chrome, and tracked adding the modal-backdrop divs.



回答21:

$(window).scroll(function(){
    if($(\'.modal.in\').length && !$(\'body\').hasClass(\'modal-open\'))
    {
              $(\'body\').addClass(\'modal-open\');
    }

});


回答22:

Check this out! This solution solved the problem for me, few simple CSS lines:

.modal:nth-of-type(even) {
z-index: 1042 !important;
}
.modal-backdrop.in:nth-of-type(even) {
    z-index: 1041 !important;
}

Here is a link to where I found it: Bootply Just make sure that the .modual that need to appear on Top is second in HTML code, so CSS can find it as \"even\".



回答23:

No script solutions , using only css given you have two layers of modals, set the 2nd modal to a higher z index

.second-modal { z-index: 1070 }

div.modal-backdrop + div.modal-backdrop {
   z-index: 1060; 
}


回答24:

Sometimes sequence may causes the mess! Write first modal first then second modal



回答25:

please follow instruction
1. first give any id to your modal popup which you want to give perioty eX: id=\'testmodal\'
2. In style you can defile a css like below, value 2147483647 is the highest value which you can give as a z index.

#testmodal.fade.in{
    z-index: 2147483647;
}

this css class will apply on your modal in which you want to apply,because it will first search id=testmodal if you have more then one popup then you can set \"z-index\" as per your priority ,\"mean higher priority will get higher z-index value