Twitter Bootstrap modal on mobile devices - android

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?

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

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.
Why it works:
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.

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

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.

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

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();

My solution...
Ver en jsfiddle
//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');
}

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

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

For me just $('[data-toggle="modal"]').click(function(){}); is working fine.

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

Related

media query does not work correctly for mobile device - phone

I've looked at similar questions on here and tried what they've shown, where people have resolved issues, but no luck for me.
I've got a basic bootstrap 4.4.1 CSS file hooked in and then my own custom CSS file as well.
At the bottom of it, I plug in the media queries:
#media screen and (min-width:176px) and (max-width: 459px) {
divboxshadow_rt {
width: 320%;
float:left;
background-color: #FFFCCC;
}
body {
width: 100%;
background-color: #fff;
}
.col col-md-8 px-md-6 {
width:80%; float:left
}
}
#media (min-width:460px) and (max-width: 767px) {
.col-sm-3.col-xs-12{ width:50%; float:left}
.col-sm-4.col-xs-12{ width:50%; float:left}
.col-sm-6.col-xs-12{ width:50%; float:left}
}
This actually works in the dev console looking at it in one of my browsers in responsive mode, particularly one of the iPhone flavors. I have no intention of using this paltry bkg color but it does show as I alter it.
I've tried my site in both the stock browser and Chrome. I've got Android, Galaxy Samsung 9.
Is there some code override I need to use to get this to work? Or does something here look incorrect, despite the fact it's now looking correct in two dev consoles (Chrome and Avast)?
I need the col widths or the body width actually, to be a little wider in phone mode. The div box is getting scrunched up wrongly.
I welcome any feedback you folks will give me. I added another class and revised my question below, slightly. I cannot get that one class to override its original. Am I doing that incorrectly? i.e. override divboxshadow_rt with the media query version? Actually very close now.
I have
<div class="col col-3 .px-md-6 divboxshadow_rt " >
I am attempting/needing to override the col col-3 with col col-md-8 as plugged into the media query for small devices above. Would it not override that? the col col-3 stays in tact, and isn't affected in my responsive testing. Perhaps I'm not approaching it correctly, but I thought the media query above would override the setting. No? Again, any feedback is welcomed.
// No media query necessary for xs breakpoint as it's effectively #media (min-width: 0) { ... }
You only need to write col-12 instead col-xs-12
#include media-breakpoint-up(sm) { ... }
#include media-breakpoint-up(md) { ... }
#include media-breakpoint-up(lg) { ... }
#include media-breakpoint-up(xl) { ... }
you only override the width and float styles in your custom css

Ionic has-tabs overwritten has-tabs-top

I'm working in a app with Ionic-tabs, and when i run on android device, the tabs are covering the content.
The usually fix is set has-tabs-top on the content div, but ionic has-tabs.pane are overwritten has-tabs-top css
.has-tabs.pane, .bar-footer.has-tabs.pane {
bottom: 49px;
height: auto;
}
.has-tabs-top {
top: 93px;
}
<ion-content padding="true" class="has-tabs-top">
I'm looking a way to fix it without changing the css class
You need to add this in your config method of your app module
$ionicConfigProvider.tabs.position("bottom"); //Places them at the bottom for all OS
$ionicConfigProvider.tabs.style("standard"); //Makes them all look the same across all OS

Bootstrap 3 long modal scrolling background on Android

I have a long modal that doesn't fully display on my android mobile device, the buttons are bellow the bottom of the screen, the modal doesn't scroll at all but the grayish background behind the modal does, is there any css/js trick to lock the background and allow the modal to scroll while this one is displayed ?
It may because of the modal class position is fixed...
Try put the code below to your css file, it's work for me...
#media (max-width: 767px) {
.modal {
position: absolute;
overflow:visible;
}
.modal-open {
overflow:visible;
}
}
This was supposed to be fixed with Bootstrap 3, but it is not working for me. I was able to fix wit with a combination of -webkit-overflow-scrolling CSS property and setting the max-height of my modal. Since I wanted my modal to fill the whole screen, I had to wire up some javascript to detect mobile devices and the set the max-height of my .modal-content to the viewport height of my device
Here is what I did to solve this using a library called jRespond:
Add this CSS to your modals
#media (max-width: $screen-xs-max) {
.modal-dialog {
.modal-content {
-webkit-overflow-scrolling: touch;
overflow-y: auto;
}
}
}
Add jRespond to your application
https://github.com/ten1seven/jRespond/edit/master/js/jRespond.js
Add the following code to your main.js script
/* This code handles the responsive modal for mobile */
var jRes = jRespond([{
label: 'handheld',
enter: 0,
exit: 767
}]);
jRes.addFunc({
breakpoint: 'handheld',
enter: function() {
$('.modal-content').css('max-height', $(window).height());
$(window).on('orientationchange', function () {
$('.modal-content').css('max-height', $(window).height());
});
},
exit: function () {
$('.modal-content').css('max-height', "");
$(window).off('orientationchange');
}
});

CSS -webkit-transform: translate() on Android Browser

I can't seem to get the translate property or -webkit-transform working on Android browser correctly, despite success in iOS and every desktop browser.
My 'full' solution is a small jQuery function like this:
$.fn.transition = function (properties, options) {
var $element = $(this);
options = $.extend({}, cssDefaults, options);
properties['webkitTransition'] = 'all ' + options.duration + 'ms ' + options.easing;
$element.css(properties);
return this;
};
which is called like this:
$element.css("transform","translate(1000px,0px)");
I've read in some places that Android has broken support for multiple css3 actions at the same time; however even when I replace all of this code with this simple dummy call the transform never happens:
$element.css("-webkit-transform","translate(1000px,0px)");
Am I doing something wrong that is specific to android?
I have just ran into this with
-webkit-transform: translate3d(0,200px,0);
So I am hoping this will help you. I believe this is one of the 'broken' css3 elements in the Android Browser.
I had to sub out the above code with top: 200px;
In your situation, I would try using a simple left such as left: 1000px;
remember your position statement if you need more accurate control

How to simulate :active css pseudo class in android on non-link elements?

I'd like to be able to mimic the behavior of the :active pseudo class on all elements in Android webkit. Currently, the :active syntax only works on a elements (links). Nearly all of the actionable elements in the app I'm working on are something other than a standard link tag. iOS webkit supports :active on all elements.
/* works on both android iOS webkit */
a:active {
color: blue;
}
/* works on iOS webkit, does not work on android webkit */
div:active {
color: red;
}
I've found a couple of resources [1,2] that solve similar problems, but they're both a bit heavy, and I'm wondering if there's a lighter weight solution that I'm just not able to find.
http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone
http://code.google.com/intl/ro-RO/mobile/articles/fast_buttons.html
Based on what #caffein said, here's a full implementation of this:
For all :active code, write CSS rules that look like this.
my-button:active, .my-button.fake-active {
background-color: blue;
}
Then in your document ready event add this code:
if (navigator.userAgent.toLowerCase().indexOf("android") > -1) {
$(".my-button")
.bind("touchstart", function () {
$(this).addClass("fake-active");
})
.bind("touchend", function() {
$(this).removeClass("fake-active");
});
}
This has the advantage of using the fast native :active class on iOS, and dropping back to JavaScript on Android.
Taken from my blog at http://pervasivecode.blogspot.com/2011/11/android-phonegap-active-css-pseudo.html
EDIT: I've since discovered that buttons can occasionally 'stick' in the fake-active state. The fix for this is to also handle the touchcancel event. E.g. add this to the above..
.bind("touchcancel",
function() {
var $this = $(this);
$this.removeClass("fake-active");
});
If you don't want to use any script, which adds and removes class for active state of an element, just add empty touchstart event to the body tag:
<body ontouchstart="">
This will tell the android device to handle touch events and pseudo class :active will work correctly on all elements.
No-jQuery version based on Ben Clayton's solution.
EDIT: added "touchmove" event.
function hasClass(ele,cls) {
return ele.className.match(new RegExp("(\\s|^)"+cls+"(\\s|$)"));
}
function addClass(ele,cls) {
if (!this.hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp("(\\s|^)"+cls+"(\\s|$)");
ele.className=ele.className.replace(reg," ");
}
}
window.onload = function() {
if (navigator.userAgent.toLowerCase().indexOf("android") > -1) {
var elements = document.getElementsByClassName("my-button");
for(var i = 0; i < elements.length; i++) {
var elm = elements[i];
elm.addEventListener("touchstart", function() {
addClass(this, "fake-active");}, false);
elm.addEventListener("touchmove", function() {
removeClass(this, "fake-active");}, false);
elm.addEventListener("touchend", function() {
removeClass(this, "fake-active");}, false);
elm.addEventListener("touchcancel", function() {
removeClass(this, "fake-active");}, false);
}
}
}
The ":active " pseudo class is triggered when you actually click or press an element.
A workaround for smartphones is to use the Javascript events: "ontouchstart" & "ontouchend".
Try using ontouchstart to modify the style and ontouchend to actually trigger the action.
Since I can't comment, I'm going to add another answer here.
Nadzeya suggested the following solution:
<body ontouchstart="">
This does work as described, but I believe it may also have an unintended consequence.
There has been a problem on our site where buttons would occasionally stop working. In fact, the button would change colors (as if it was pressed) but the click event wouldn't fire. Even submit buttons on forms would fail to submit the form (no Javascript involved), even after appearing pressed.
Today, I saw the problem again. On a whim, I removed this attribute and the problem went away. I then added it again and the problem came back.
Since I can't reproduce the problem reliably, I can't be certain that this was the cause, but for now I'm going to leave the tag off and solve the :active problem another way.
try this. It works for me perfectly on Android
.my-button {
-webkit-tap-highlight-color: blue;
}
Trying add this code to your HTML:
<script>
document.body.addEventlistener('touchstart',function(){},false);
</script>
I got an easy alternate solution. This however requires you to change from div tag to a tag.
<a class="html5logo" href="javascript:void(0);" ontouchstart="return true;"></a>
.html5logo {
display: block;
width: 128px;
height: 128px;
background: url(/img/html5-badge-128.png) no-repeat;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: transparent; /* For some Androids */
}
.html5logo:active {
-webkit-transform: scale3d(0.9, 0.9, 1);
}
Please find the source at phone gap tutorial
you just need put this code in your document:
<script type="application/x-javascript">document.addEventListener('touchmove', function(e){e.preventDefault();}, false);</script>

Categories

Resources