Eu preciso que a sobreposição seja exibida acima do primeiro modal, não na parte de trás.
Eu tentei mudar o z-index
de .modal-backdrop
, mas isso se torna uma bagunça.
Em alguns casos, tenho mais de dois modais na mesma página.
Eu preciso que a sobreposição seja exibida acima do primeiro modal, não na parte de trás.
Eu tentei mudar o z-index
de .modal-backdrop
, mas isso se torna uma bagunça.
Em alguns casos, tenho mais de dois modais na mesma página.
Respostas:
Depois de ver muitas correções para isso, e nenhuma delas era exatamente o que eu precisava, encontrei uma solução ainda mais curta, inspirada em @YermoLamers e @Ketwaroo.
Correção do índice z do pano de fundo
Esta solução usa um setTimeout
porque .modal-backdrop
não é criado quando o evento show.bs.modal
é disparado.
$(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);
});
.modal
criados na página (mesmo modais dinâmicos)Se você não gostar do z-index codificado por algum motivo, poderá calcular o z-index mais alto na página como este:
var zIndex = Math.max.apply(null, Array.prototype.map.call(document.querySelectorAll('*'), function(el) {
return +el.style.zIndex;
})) + 10;
Correção da barra de rolagem
Se você possui um modal em sua página que excede a altura do navegador, não é possível rolar nele ao fechar um segundo modal. Para corrigir este add:
$(document).on('hidden.bs.modal', '.modal', function () {
$('.modal:visible').length && $(document.body).addClass('modal-open');
});
Versões
Esta solução foi testada com o bootstrap 3.1.0 - 3.3.5
.not(this)
para a segunda linha) para fazê-lo funcionar com datepicker de bootstrap var zIndex = 1040 + (10 * $('.modal:visible').not(this).length);
Sei que uma resposta foi aceita, mas sugiro fortemente que não hackear o bootstrap para corrigir isso.
Você pode obter facilmente o mesmo efeito conectando os manipuladores de eventos mostrado.bs.modal e hidden.bs.modal e ajustando o índice z lá.
Aqui está um exemplo de trabalho
Um pouco mais de informação está disponível aqui.
Esta solução funciona automaticamente com pilhas arbitrariamente profundamente modais.
O código fonte do script:
$(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');
});
});
Uma versão mais curta, baseada na sugestão de Yermo Lamers, parece funcionar bem. Mesmo com animações básicas, como o fade in / out e até o louco jornal do batman giram. 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');
});
modal-open
classe no elemento body: jsfiddle.net/vkyjocyn
Combinando a resposta de A1rPun com a sugestão de StriplingWarrior, eu vim com isso:
$(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');
Funciona mesmo para modais dinâmicos adicionados após o fato e remove o problema da segunda barra de rolagem. A coisa mais notável para a qual achei útil foi a integração de formulários dentro de modais com feedback de validação dos alertas do Bootbox, pois eles usam modais dinâmicos e, portanto, exigem que você vincule o evento ao documento em vez de ao .modal, já que isso apenas o anexa aos existentes. modais.
Eu criei um plugin Bootstrap que incorpora muitas das idéias postadas aqui.
Demonstração no Bootply: http://www.bootply.com/cObcYInvpq
Github: https://github.com/jhaygt/bootstrap-multimodal
Ele também soluciona o problema com modais sucessivos, tornando o cenário cada vez mais escuro. Isso garante que apenas um pano de fundo seja visível a qualquer momento:
if(modalIndex > 0)
$('.modal-backdrop').not(':first').addClass('hidden');
O índice z do pano de fundo visível é atualizado nos eventos show.bs.modal
e hidden.bs.modal
:
$('.modal-backdrop:first').css('z-index', MultiModal.BASE_ZINDEX + (modalIndex * 20));
Ao resolver os Modais de empilhamento, rola a página principal quando um é fechado, descobri que as versões mais recentes do Bootstrap (pelo menos desde a versão 3.0.3) não exigem código adicional para empilhar os modais.
Você pode adicionar mais de um modal (obviamente, com um ID diferente) à sua página. O único problema encontrado ao abrir mais de um modal será que ao fechar um, remova omodal-open
classe do seletor de corpo.
Você pode usar o seguinte código Javascript para adicionar novamente modal-open
:
$('.modal').on('hidden.bs.modal', function (e) {
if($('.modal').hasClass('in')) {
$('body').addClass('modal-open');
}
});
No caso de não precisar do efeito de pano de fundo para o modal empilhado, você pode definir data-backdrop="false"
.
Versão 3.1.1. fixo Corrigir o cenário modal sobrepondo a barra de rolagem do modal , mas a solução acima também parece funcionar com versões anteriores.
Finalmente resolvido. Eu testei de várias maneiras e funciona bem.
Aqui está a solução para qualquer pessoa que tenha o mesmo problema: Altere a função Modal.prototype.show (em bootstrap.js ou modal.js)
DE:
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element
.addClass('in')
.attr('aria-hidden', false)
that.enforceFocus()
PARA:
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()
É a melhor maneira que encontrei: verifique quantos modais estão abertos e altere o índice z do modal e o pano de fundo para um valor mais alto.
Se você está procurando a solução Bootstrap 4, é fácil usar CSS puro:
.modal.fade {
background: rgba(0,0,0,0.5);
}
Tente adicionar o seguinte ao seu JS no bootply
$('#myModal2').on('show.bs.modal', function () {
$('#myModal').css('z-index', 1030); })
$('#myModal2').on('hidden.bs.modal', function () {
$('#myModal').css('z-index', 1040); })
Explicação:
Depois de brincar com os atributos (usando a ferramenta de desenvolvimento do Chrome), percebi que qualquer z-index
valor abaixo 1031
colocará as coisas por trás do pano de fundo.
Então, usando alças de eventos modais de Bootstrap eu definir o z-index
que 1030
. Se #myModal2
for mostrado e z-index
volte para 1040
se #myModal2
estiver oculto.
Sempre que você executa a função sys.showModal, incremente o índice z e defina-o como seu novo 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');
A solução para isso foi NÃO usar a classe "fade" nos meus divs modais.
Nenhuma solução de script, usando apenas css, pois você tem duas camadas de modais, defina o segundo modal para um índice z mais alto
.second-modal { z-index: 1070 }
div.modal-backdrop + div.modal-backdrop {
z-index: 1060;
}
Se você deseja que um modal específico apareça sobre outro modal aberto, tente adicionar o HTML do modal mais alto após o outro modal div
.
Isso funcionou para mim:
<div id="modal-under" class="modal fade" ... />
<!--
This modal-upper should appear on top of #modal-under when both are open.
Place its HTML after #modal-under. -->
<div id="modal-upper" class="modal fade" ... />
Minha solução para o bootstrap 4, trabalhando com profundidade ilimitada de modais e modal dinâmico.
$('.modal').on('show.bs.modal', function () {
var $modal = $(this);
var baseZIndex = 1050;
var modalZIndex = baseZIndex + ($('.modal.show').length * 20);
var backdropZIndex = modalZIndex - 10;
$modal.css('z-index', modalZIndex).css('overflow', 'auto');
$('.modal-backdrop.show:last').css('z-index', backdropZIndex);
});
$('.modal').on('shown.bs.modal', function () {
var baseBackdropZIndex = 1040;
$('.modal-backdrop.show').each(function (i) {
$(this).css('z-index', baseBackdropZIndex + (i * 20));
});
});
$('.modal').on('hide.bs.modal', function () {
var $modal = $(this);
$modal.css('z-index', '');
});
Cada modal deve receber um ID diferente e cada link deve ser direcionado para um ID modal diferente. Portanto, deve ser algo assim:
<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>
...
EDIT: O Bootstrap 3.3.4 resolveu esse problema (e outros problemas modais), portanto, se você puder atualizar o CSS e o JS do bootstrap, essa seria a melhor solução. Se você não conseguir atualizar a solução abaixo, ainda funcionará e essencialmente fará o mesmo que o bootstrap 3.3.4 (recalcular e aplicar preenchimento).
Como apontou Bass Jobsen, as versões mais recentes do Bootstrap têm o índice z resolvido. A classe modal-open e padding-right ainda eram problemas para mim, mas esse script inspirado na solução Yermo Lamers resolve isso. Basta soltá-lo no seu arquivo JS e aproveitar.
$(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'));
});
Veja isso! Esta solução resolveu o problema para mim, algumas linhas CSS simples:
.modal:nth-of-type(even) {
z-index: 1042 !important;
}
.modal-backdrop.in:nth-of-type(even) {
z-index: 1041 !important;
}
Aqui está um link para onde eu o encontrei: Bootply Apenas verifique se o .modual que precisa aparecer no Top é o segundo no código HTML, para que o CSS possa encontrá-lo como "par".
trabalhar para abrir / fechar multi-modais
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
Para mim, essas regras simples do scss funcionaram perfeitamente:
.modal.show{
z-index: 1041;
~ .modal.show{
z-index: 1043;
}
}
.modal-backdrop.show {
z-index: 1040;
+ .modal-backdrop.show{
z-index: 1042;
}
}
Se essas regras fizerem com que o modal errado esteja no topo no seu caso, altere a ordem dos seus divs modais ou altere (ímpar) para (par) no scss acima.
Aqui estão algumas CSS usando nth-of-type
seletores que parecem funcionar:
.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
Eu tive um cenário semelhante e, depois de um pouco de pesquisa e desenvolvimento, encontrei uma solução. Embora eu não seja muito bom em JS, consegui escrever uma pequena consulta.
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">×</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);
});
Adicionar variável global no modal.js
var modalBGIndex = 1040; // modal backdrop background
var modalConIndex = 1042; // modal container data
// mostra a função dentro da variável add - 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
As outras soluções não funcionaram para mim imediatamente. Acho que talvez porque esteja usando uma versão mais recente do Bootstrap (3.3.2) .... a sobreposição estava aparecendo na parte superior da caixa de diálogo modal.
Refatorei um pouco o código e comentei a parte que estava ajustando o cenário modal. Isso corrigiu o problema.
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');
});
Como observação, se você quiser usar isso no AngularJs, basta colocar o código dentro do método .run () do seu módulo.
Infelizmente, não tenho reputação de comentar, mas deve-se observar que a solução aceita com a linha de base codificada de um índice z 1040 parece ser superior ao cálculo do zIndex que tenta encontrar o máximo de zIndex sendo processado na página.
Parece que determinadas extensões / plugins dependem do conteúdo DOM de nível superior, o que torna o cálculo .Max um número tão obscenamente grande que não pode mais incrementar o zIndex. Isso resulta em um modal em que a sobreposição aparece incorretamente sobre o modal (se você usar as ferramentas Firebug / Google Inspector, verá um zIndex na ordem de 2 ^ n - 1)
Não consegui isolar o motivo específico pelas quais as várias formas do Math.Max for z-Index levam a esse cenário, mas isso pode acontecer e parecerá exclusivo para alguns usuários. (Meus testes gerais no browserstack tinham esse código funcionando perfeitamente).
Espero que isso ajude alguém.
No meu caso, o problema foi causado por uma extensão do navegador que inclui os arquivos bootstrap.js, nos quais o evento show manipulado duas vezes e duas modal-backdrop
divs são adicionadas, mas ao fechar o modal, apenas um deles é removido.
Constatou que, adicionando um ponto de interrupção de modificação de subárvore ao elemento body no chrome, e rastreava a adição dos modal-backdrop
divs.
$(window).scroll(function(){
if($('.modal.in').length && !$('body').hasClass('modal-open'))
{
$('body').addClass('modal-open');
}
});
Atualização: 22.01.2019, 13.41 Otimizei a solução com jhay, que também suporta o fechamento e a abertura de diálogos iguais ou diferentes ao, por exemplo, passar de um dado detalhado para outro para frente ou para trás.
(function ($, window) {
'use strict';
var MultiModal = function (element) {
this.$element = $(element);
this.modalIndex = 0;
};
MultiModal.BASE_ZINDEX = 1040;
/* Max index number. When reached just collate the zIndexes */
MultiModal.MAX_INDEX = 5;
MultiModal.prototype.show = function (target) {
var that = this;
var $target = $(target);
// Bootstrap triggers the show event at the beginning of the show function and before
// the modal backdrop element has been created. The timeout here allows the modal
// show function to complete, after which the modal backdrop will have been created
// and appended to the DOM.
// we only want one backdrop; hide any extras
setTimeout(function () {
/* Count the number of triggered modal dialogs */
that.modalIndex++;
if (that.modalIndex >= MultiModal.MAX_INDEX) {
/* Collate the zIndexes of every open modal dialog according to its order */
that.collateZIndex();
}
/* Modify the zIndex */
$target.css('z-index', MultiModal.BASE_ZINDEX + (that.modalIndex * 20) + 10);
/* we only want one backdrop; hide any extras */
if (that.modalIndex > 1)
$('.modal-backdrop').not(':first').addClass('hidden');
that.adjustBackdrop();
});
};
MultiModal.prototype.hidden = function (target) {
this.modalIndex--;
this.adjustBackdrop();
if ($('.modal.in').length === 1) {
/* Reset the index to 1 when only one modal dialog is open */
this.modalIndex = 1;
$('.modal.in').css('z-index', MultiModal.BASE_ZINDEX + 10);
var $modalBackdrop = $('.modal-backdrop:first');
$modalBackdrop.removeClass('hidden');
$modalBackdrop.css('z-index', MultiModal.BASE_ZINDEX);
}
};
MultiModal.prototype.adjustBackdrop = function () {
$('.modal-backdrop:first').css('z-index', MultiModal.BASE_ZINDEX + (this.modalIndex * 20));
};
MultiModal.prototype.collateZIndex = function () {
var index = 1;
var $modals = $('.modal.in').toArray();
$modals.sort(function(x, y)
{
return (Number(x.style.zIndex) - Number(y.style.zIndex));
});
for (i = 0; i < $modals.length; i++)
{
$($modals[i]).css('z-index', MultiModal.BASE_ZINDEX + (index * 20) + 10);
index++;
};
this.modalIndex = index;
this.adjustBackdrop();
};
function Plugin(method, target) {
return this.each(function () {
var $this = $(this);
var data = $this.data('multi-modal-plugin');
if (!data)
$this.data('multi-modal-plugin', (data = new MultiModal(this)));
if (method)
data[method](target);
});
}
$.fn.multiModal = Plugin;
$.fn.multiModal.Constructor = MultiModal;
$(document).on('show.bs.modal', function (e) {
$(document).multiModal('show', e.target);
});
$(document).on('hidden.bs.modal', function (e) {
$(document).multiModal('hidden', e.target);
});}(jQuery, window));
Verifique a contagem de modais e adicione o valor ao pano de fundo como z-index
var zIndex = 1500 + ($('.modal').length*2) + 1;
this.popsr.css({'z-index': zIndex});
this.popsr.on('shown.bs.modal', function () {
$(this).next('.modal-backdrop').css('z-index', zIndex - 1);
});
this.popsr.modal('show');