Bootstrap modals don't work correctly on Android and iOS. The issue tracker acknowledges the problem but does not offer a working solution:
Modals in 2.0 are broken on mobile.
Modal window in 2.0 not positioning properly
The screen darkens but the modal itself is not visible in the viewport. It's possible to find it at the top of the page. The problem occurs when you've scrolled down on the page.
Here is a relevant portion of bootstrap-responsive.css:
.modal {
position:fixed;
top:50%;
left:50%;
z-index:1050;
max-height:500px;
overflow:auto;
width:560px;
background-color:#fff;
border:1px solid #999;
-webkit-border-radius:6px;
-moz-border-radius:6px;
border-radius:6px;
-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);
-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);
box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);
-webkit-background-clip:padding-box;
-moz-background-clip:padding-box;
background-clip:padding-box;
margin:-250px 0 0 -280px;
}
Is there a fix I can apply?
This question is related to
android
ios
mobile
webkit
twitter-bootstrap
EDIT: An unofficial Bootstrap Modal modification has been built to address responsive/mobile issues. This is perhaps the simplest and easiest way to remedy the problem.
There has since been a fix found in one of the issues you discussed earlier
in bootstrap-responsive.css
.modal {
position: fixed;
top: 3%;
right: 3%;
left: 3%;
width: auto;
margin: 0;
}
.modal-body {
height: 60%;
}
and in bootstrap.css
.modal-body {
max-height: 350px;
padding: 15px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
Albeit this question is quite old, some people still may stumble upon it when looking for solution to improve UX of modals on mobile phones.
I've made a lib to improve Bootrsrap modals' behavior on phones.
Bootstrap 3: https://github.com/keaukraine/bootstrap-fs-modal
Bootstrap 4: https://github.com/keaukraine/bootstrap4-fs-modal
Mainly Nexus 7 modal issue , modal was going down the screen
.modal:before {
content: '';
display: inline-block;
height: 50%; (the value was 100% for center the modal)
vertical-align: middle;
margin-right: -4px;
}
Admittedly, I haven't tried any of the solutions listed above but I was (eventually) jumping for joy when I tried jschr's Bootstrap-modal project in Bootstrap 3 (linked to in the top answer). The js was giving me trouble so I abandoned it (maybe mine was a unique issue or it works fine for Bootstrap 2) but the CSS files on their own seem to do the trick in Android's native 2.3.4 browser.
In my case, I've resorted so far to using (sub-optimal) user-agent detection before using the overrides to allow expected behaviour in modern phones.
For example, if you wanted all Android phones ver 3.x and below only to use the full set of hacks you could add a class "oldPhoneModalNeeded" to the body after user agent detection using javascript and then modify jschr's Bootstrap-modal CSS properties to always have .oldPhoneModalNeeded as an ancestor.
The solution by niftylettuce in issue 2130 seems to fix modals in all mobile platforms...
9/1/12 UPDATE: The fix has been updated here: twitter bootstrap jquery plugins
(the code below is older but still works)
// # Twitter Bootstrap modal responsive fix by @niftylettuce
// * resolves #407, #1017, #1339, #2130, #3361, #3362, #4283
// <https://github.com/twitter/bootstrap/issues/2130>
// * built-in support for fullscreen Bootstrap Image Gallery
// <https://github.com/blueimp/Bootstrap-Image-Gallery>
// **NOTE:** If you are using .modal-fullscreen, you will need
// to add the following CSS to `bootstrap-image-gallery.css`:
//
// @media (max-width: 480px) {
// .modal-fullscreen {
// left: 0 !important;
// right: 0 !important;
// margin-top: 0 !important;
// margin-left: 0 !important;
// }
// }
//
var adjustModal = function($modal) {
var top;
if ($(window).width() <= 480) {
if ($modal.hasClass('modal-fullscreen')) {
if ($modal.height() >= $(window).height()) {
top = $(window).scrollTop();
} else {
top = $(window).scrollTop() + ($(window).height() - $modal.height()) / 2;
}
} else if ($modal.height() >= $(window).height() - 10) {
top = $(window).scrollTop() + 10;
} else {
top = $(window).scrollTop() + ($(window).height() - $modal.height()) / 2;
}
} else {
top = '50%';
if ($modal.hasClass('modal-fullscreen')) {
$modal.stop().animate({
marginTop : -($modal.outerHeight() / 2)
, marginLeft : -($modal.outerWidth() / 2)
, top : top
}, "fast");
return;
}
}
$modal.stop().animate({ 'top': top }, "fast");
};
var show = function() {
var $modal = $(this);
adjustModal($modal);
};
var checkShow = function() {
$('.modal').each(function() {
var $modal = $(this);
if ($modal.css('display') !== 'block') return;
adjustModal($modal);
});
};
var modalWindowResize = function() {
$('.modal').not('.modal-gallery').on('show', show);
$('.modal-gallery').on('displayed', show);
checkShow();
};
$(modalWindowResize);
$(window).resize(modalWindowResize);
$(window).scroll(checkShow);
We use this code to center the Bootstrap modal dialogs when they open. I haven't had any issue with them on iOS while using this but I'm not sure if it will work for Android.
$('.modal').on('show', function(e) {
var modal = $(this);
modal.css('margin-top', (modal.outerHeight() / 2) * -1)
.css('margin-left', (modal.outerWidth() / 2) * -1);
return this;
});
Gil's answer holds promise (the library he linked to) --- but for the time being, it still doesn't work when scrolled down on the mobile device.
I solved the issue for myself using just a snippet of CSS at the end of my CSS files:
@media (max-width: 767px) {
#content .modal.fade.in {
top: 5%;
}
}
The #content
selector is simply an id that wraps my html so I can override Bootstrap's specificity (set to your own id wrapping your modal html).
The downside: It's not centered vertically on the mobile devices.
The upside: It's visible, and on smaller devices, a reasonably sized modal will take up much of the screen, so the "non-centering" won't be as apparent.
When you're at low screen sizes with Bootstrap's responsive CSS, for devices with smaller screens, it sets .modal.fade.in's 'top' to 'auto'. For some reason the mobile webkit browsers seem to have a hard time with figuring out the vertical placement with the "auto" assignment. So just switch it back to a fixed value and it works great.
Since the modal is already set to postition: absolute, the value is relative to the viewport's height, not the document height, so it works no matter how long the page is or where you're scrolled to.
For me just $('[data-toggle="modal"]').click(function(){});
is working fine.
Found a very hacky solution to this problem, but it works. I added a class to the link that is used to open the modal (With the data-target), then using Jquery, added a click event to that class that gets the data-target, finds the modal it is supposed to open, and then opens it via Javascript. Works just fine for me. I also added a mobile check on mine so that it only runs on mobile, but that's not required.
$('.forceOpen').click(function() {
var id = $(this).attr('data-target');
$('.modal').modal('hide');
$(id).modal('show');
});
OK this does fix it I tried it today Sept 5-2012 but you have to be sure to check out the demo
The solution by niftylettuce in issue 2130 seems to fix modals in all mobile platforms...
9/1/12 UPDATE: The fix has been updated here: twitter bootstrap jquery plugins
here is the link to the Demo It works great heres the code I used
title_dialog.modal();
title_dialog.modalResponsiveFix({})
title_dialog.touchScroll();
you can add this property globally in javascript:
if( navigator.userAgent.match(/iPhone|iPad|iPod/i) ) {
var styleEl = document.createElement('style'), styleSheet;
document.head.appendChild(styleEl);
styleSheet = styleEl.sheet;
styleSheet.insertRule(".modal { position:absolute; bottom:auto; }", 0);
}
My solution...
//Fix modal mobile Boostrap 3
function Show(id){
//Fix CSS
$(".modal-footer").css({"padding":"19px 20px 20px","margin-top":"15px","text-align":"right","border-top":"1px solid #e5e5e5"});
$(".modal-body").css("overflow-y","auto");
//Fix .modal-body height
$('#'+id).on('shown.bs.modal',function(){
$("#"+id+">.modal-dialog>.modal-content>.modal-body").css("height","auto");
h1=$("#"+id+">.modal-dialog").height();
h2=$(window).height();
h3=$("#"+id+">.modal-dialog>.modal-content>.modal-body").height();
h4=h2-(h1-h3);
if($(window).width()>=768){
if(h1>h2){
$("#"+id+">.modal-dialog>.modal-content>.modal-body").height(h4);
}
$("#"+id+">.modal-dialog").css("margin","30px auto");
$("#"+id+">.modal-dialog>.modal-content").css("border","1px solid rgba(0,0,0,0.2)");
$("#"+id+">.modal-dialog>.modal-content").css("border-radius",6);
if($("#"+id+">.modal-dialog").height()+30>h2){
$("#"+id+">.modal-dialog").css("margin-top","0px");
$("#"+id+">.modal-dialog").css("margin-bottom","0px");
}
}
else{
//Fix full-screen in mobiles
$("#"+id+">.modal-dialog>.modal-content>.modal-body").height(h4);
$("#"+id+">.modal-dialog").css("margin",0);
$("#"+id+">.modal-dialog>.modal-content").css("border",0);
$("#"+id+">.modal-dialog>.modal-content").css("border-radius",0);
}
//Aply changes on screen resize (example: mobile orientation)
window.onresize=function(){
$("#"+id+">.modal-dialog>.modal-content>.modal-body").css("height","auto");
h1=$("#"+id+">.modal-dialog").height();
h2=$(window).height();
h3=$("#"+id+">.modal-dialog>.modal-content>.modal-body").height();
h4=h2-(h1-h3);
if($(window).width()>=768){
if(h1>h2){
$("#"+id+">.modal-dialog>.modal-content>.modal-body").height(h4);
}
$("#"+id+">.modal-dialog").css("margin","30px auto");
$("#"+id+">.modal-dialog>.modal-content").css("border","1px solid rgba(0,0,0,0.2)");
$("#"+id+">.modal-dialog>.modal-content").css("border-radius",6);
if($("#"+id+">.modal-dialog").height()+30>h2){
$("#"+id+">.modal-dialog").css("margin-top","0px");
$("#"+id+">.modal-dialog").css("margin-bottom","0px");
}
}
else{
//Fix full-screen in mobiles
$("#"+id+">.modal-dialog>.modal-content>.modal-body").height(h4);
$("#"+id+">.modal-dialog").css("margin",0);
$("#"+id+">.modal-dialog>.modal-content").css("border",0);
$("#"+id+">.modal-dialog>.modal-content").css("border-radius",0);
}
};
});
//Free event listener
$('#'+id).on('hide.bs.modal',function(){
window.onresize=function(){};
});
//Mobile haven't scrollbar, so this is touch event scrollbar implementation
var y1=0;
var y2=0;
var div=$("#"+id+">.modal-dialog>.modal-content>.modal-body")[0];
div.addEventListener("touchstart",function(event){
y1=event.touches[0].clientY;
});
div.addEventListener("touchmove",function(event){
event.preventDefault();
y2=event.touches[0].clientY;
var limite=div.scrollHeight-div.clientHeight;
var diff=div.scrollTop+y1-y2;
if(diff<0)diff=0;
if(diff>limite)diff=limite;
div.scrollTop=diff;
y1=y2;
});
//Fix position modal, scroll to top.
$('html, body').scrollTop(0);
//Show
$("#"+id).modal('show');
}
Source: Stackoverflow.com