Below you find a situation where the specified z-index of the modal is higher than the z-index of the modal-backdrop. Still, there are many situations that the backdrop will be on top of the modal. So, the user cannot access the modal. You find an example below in picture and code.
What are the rules for getting a modal always on top of the backdrop? Especially, I am looking for the 'position' options for the 'container' class. I simplified my issue by just using a simple container. In reality that container may have different positions. I used jQuery just to simplify the context.
Below you find HTML with 4 examples when a modal backdrop appears to be 'above' the modal. An example is:
Switching the backdrop 'off' is NOT a solution.
I read this great post and this article, but find it hard to apply to the deserved cases. I experimented with the 'stack context' in combination with placing the modal-divs inside or outside the container-div.
$(document).ready(function() {
$("#myBtn").click(function() {
$("#myModal").modal({
backdrop: true
});
});
});
.container {
z-index: 85;
/* Backdrop overrules: situation 1: container position: relative; && modal position: no position with modal inside container-div */
/* Backdrop overrules: situation 2: container position: absolute; && modal position: no position with modal inside container-div */
/* Less important ... */
/* Backdrop overrules: situation 3: container position: relative; && modal-div position: static with modal outside container-div */
/* Backdrop overrules: situation 4: container position: absolute; && modal-div position: static with modal outside container-div */
position: absolute;
}
.modal {
background-color: red;
z-index: 100;
}
.modal-backdrop {
background-color: green;
z-index: 90;
}
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Modal and backdrops</h2>
<p>Simulate a backdrop that overrules a modal</p>
<button type="button" class="btn btn-info btn-md" id="myBtn">Modal with Overlay</button>
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal with Overlay</h4>
</div>
<div class="modal-body">
<p>This modal has a overlay.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</body>
Updates: removing the z-index from the modal is indeed correct. It will however not solve the current issue.
Digging deeper, I have these 2 screenshots. Before launching the popup. And after launching the popup; the modal-backdrop is dynamically added near the end of the DOM. I guess outside the context stack of the modal-div.
This is a situation inherited in maintaining a complex web page. The modal-div is inside a library component. The library comp is positioned with 'relative'.
... and after launching the popup:
I suggest you to slightly change the backdrop
function in the bootstrap v3.4.1 modal, and insert .modal-backdrop
directly into .modal
:
$(document).ready(function() {
// https://github.com/twbs/bootstrap/blob/f17f882df292b29323f1e1da515bd16f326cee4a/js/modal.js#L186
$.fn.modal.Constructor.prototype.backdrop = function (callback) {
var Modal = $.fn.modal.Constructor /* + */
var that = this
var animate = this.$element.hasClass('fade') ? 'fade' : ''
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
this.$backdrop = $(document.createElement('div'))
.addClass('modal-backdrop ' + animate)
// .appendTo(this.$body)
this.$element.append(this.$backdrop); /* + */
this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
// if (this.ignoreBackdropClick) {
// this.ignoreBackdropClick = false
// return
// }
// if (e.target !== e.currentTarget) return
if (e.target !== this.$backdrop[0]) return /* + */
this.options.backdrop == 'static'
? this.$element[0].focus()
: this.hide()
}, this))
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
this.$backdrop.addClass('in')
if (!callback) return
doAnimate ?
this.$backdrop
.one('bsTransitionEnd', callback)
.emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callback()
} else if (!this.isShown && this.$backdrop) {
this.$backdrop.removeClass('in')
var callbackRemove = function () {
that.removeBackdrop()
callback && callback()
}
$.support.transition && this.$element.hasClass('fade') ?
this.$backdrop
.one('bsTransitionEnd', callbackRemove)
.emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callbackRemove()
} else if (callback) {
callback()
}
}
$("#myBtn").click(function() {
$("#myModal").modal({
backdrop: true
});
});
});
.container {
z-index: 85;
/* Backdrop overrules: situation 1: container position: relative; && modal position: no position with modal inside container-div */
/* Backdrop overrules: situation 2: container position: absolute; && modal position: no position with modal inside container-div */
/* Less important ... */
/* Backdrop overrules: situation 3: container position: relative; && modal-div position: static with modal outside container-div */
/* Backdrop overrules: situation 4: container position: absolute; && modal-div position: static with modal outside container-div */
position: absolute;
}
.modal {
background-color: red;
}
.modal .modal-backdrop {
background-color: green;
}
.modal-dialog {
z-index: 999999;
}
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Modal and backdrops</h2>
<p>Simulate a backdrop that overrules a modal</p>
<button type="button" class="btn btn-info btn-md" id="myBtn">Modal with Overlay</button>
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal with Overlay</h4>
</div>
<div class="modal-body">
<p>This modal has a overlay.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</body>
Any other modals will work as well.