Edit: The main issue is this: overflow: hidden and overflow: auto affect fixed positioned elements in iOS.
So if I have a fixed positioned modal dialog in a component within a scrolling feature of the page, that element is not displayed wherever it exceeds the bounds of its parent. This is really messed up, as it's not how fixed positioning works on any other system. So what's the official response to this?
Original post:
I have a modal dialog that works fine on desktop and Android, but on any browser on my iPad, the modal dialog, including the modal overlay, gets hidden wherever it exceeds the boundaries of its parent container (even though it is fixed positioned). I know that this isn't how overflow: auto is supposed to work, because it works just fine on all other devices. Anyone else experienced this? I'm sure it has something to do with how iOS handles fixed positions.
Anyway, here's some code:
HTML:
<confirm-dialog ng-if="$ctrl.confirmDlgShowing" on-close="$ctrl.closeDlgs()" on-confirm="$ctrl.deleteInstance()" class="ng-scope ng-isolate-scope">
<div class="modal general modal"><div class="modal-window"><div class="modal-inner" ng-transclude="">
<div style="position:relative" class="ng-scope">
<label class="modal-close" ng-click="$ctrl.onClose()"></label>
<div class="page-heading">
<h2>Are you sure?</h2>
</div>
<input class="btn" type="button" value="Yes" ng-click="$ctrl.confirm()">
<input class="btn" type="button" value="No" ng-click="$ctrl.onClose()">
</div>
</div></div></div>
</confirm-dialog>
SASS:
.container {
overflow: auto;
.modal-window {
// overlay
#include transition(opacity 0.25s ease);
#include position(fixed, 0px 0px 0px 0px);
background: rgba(0,0,0, 0.6);
padding-top: 0.6em;
text-align: left;
z-index: 999999999;
margin: 0 !important;
.modal-bg {
#include position(absolute, 0px 0px 0px 0px);
cursor: pointer;
}
}
.modal-inner {
#include transition(opacity 0.25s ease);
background: $modal-background;
border-radius: $base-border-radius;
display: table;
margin: 70px auto;
max-height: 80%;
overflow: auto;
padding: $modal-padding / 2;
z-index: 1000000000;
min-width: 400px;
#media(max-width: $medium-screen) {
max-height: 70%;
padding: $modal-padding;
}
}
}
Here's the workaround we finally came up with--a new directive to replace ng-if on our modals that places the object on the body. Plays nicely with other Angular bindings too.
angular.module('app').directive('rootIf', function()
{
return {
restrict: 'A',
link: function (scope, $elm, attrs)
{
scope.$watch(attrs.rootIf, onChangeRootIf);
function onChangeRootIf()
{
if (scope.$eval(attrs.rootIf))
$("body").children().first().before($elm);
else
$elm.detach();
}
}
}
});
Related
I have one div containing an image and a translucent window over it that is draggable and resizable. I am using the parent div as the containment parameter for the respective jQuery UI interactions. But when I resize the window, I can only resize it to 10px less than the parent width. No matter which image I use. No issues resizing to the full height. No issues dragging to the far right or bottom.
Here is the code (Try it here - JS Fiddle)
HTML:
<div id="container">
<div id="navi">
<img src="http://www.mountainevolution.com/Cento%20Fonti/images/dscn7587.jpg" />
</div>
<div id="infoi">
</div>
</div>
CSS:
#container {
width: 100px;
height: 100px;
position: relative;
}
#infoi {
position: absolute;
top: 0px;
left: 0px;
background-color: lightblue;
border: solid 1px navy;
width: 100px;
height: 100px;
opacity: 0.5;
}
#navi {
padding: 0px;
position: absolute;
}
#navi img {
display: block;
}
JS:
$("#infoi").draggable({
containment: "#navi"
});
$("#infoi").resizable({
containment: "#navi"
});
I have played around with margins and padding, and also looked at other questions on StackOverflow. None of them are similar to mine. There are some questions on problems with using resizable and draggable together. In my case, removing draggable does not affect the issue, so I don't think it is a problem with using them together.
I recently asked this question about jQuery animation not working on iPad after sleep/resume when run from a homescreen icon. That question received zero comments and zero answers in the two weeks since I asked it.
I spent some more time investigating, creating small tests to understand what works and what doesn't - and confirmed that jQuery is not at fault here, but rather the mobile Safari.
I created this simple test: http://jsfiddle.net/87r3vfe1/ - which does not use jQuery at all and instead uses plain javascript and CSS transition animation. This works perfectly fine in the actual safari - straight away and after sleep/resume - and works from the homescreen icon when just started. However after the sleep/resume, the transition animation does not work anymore - and the screen simply changes after the indicated delay.
So, it seems like I actually found a bug in the mobile safari. Does anybody have any ideas for a workaround?
Here's the code from the fiddle.
HTML:
<div id="parent">
<div id="child1">
<div class="button" id="button1">Animate</div>
</div>
<div id="child2">
<div class="button" id="button2">Animate</div>
</div>
</div>
CSS:
body {
margin: 0px;
padding: 0px;
}
#parent {
width:100%;
height:300px;
position: relative;
}
#child1 {
position: absolute;
width:100%;
height:100%;
left: 0px;
background-color: yellow;
transition: left 400ms ease-in-out;
-webkit-transition: left 400ms ease-in-out;
}
#child2 {
position: absolute;
width:100%;
height:100%;
left:100%;
background-color: red;
transition: left 400ms ease-in-out;
-webkit-transition: left 400ms ease-in-out;
}
.button {
border: solid 1px black;
text-align: center;
width: 100px;
padding: 10px 20px;
background-color: lightGrey;
cursor: pointer;
}
Javascript:
document.onload = function() {
document.getElementById('button1').onclick = function() {
document.getElementById('child2').style.left = '0px';
document.getElementById('child1').style.left = '-100%';
};
document.getElementById('button2').onclick = function() {
document.getElementById('child1').style.left = '0px';
document.getElementById('child2').style.left = '100%';
};
};
Turns out, this was related to (or caused by) another bug in iOS 8, covered in this question
iOS 8.1.1 update fixes this bug, so with iOS 8.1.1 transition animations work correctly again.
I made a simple flippable element using common techniques and found some strange behavior in Mobile Safari on iOS 7 (older version also may be affected, unfortunately I can't test them at the moment older versions also seem to be affected), please see the images below or visit a demo directly on your iOS device.
Editable markup and stylesheet
Full screen view to visit on your iOS device
<div class="flippable">
<input id="flippable-trigger" type="checkbox">
<label for="flippable-trigger" class="flippable-faces">
<div class="flippable-face-front">
Front
</div>
<div class="flippable-face-back">
Back
</div>
</label>
</div>
body {
font: 1em/0 Arial;
background-color: silver;
}
.flippable {
position: relative;
float: left;
width: 10rem;
height: 10rem;
-webkit-perspective: 800;
}
.flippable input[type="checkbox"] {
display: none;
}
.flippable-faces,
.flippable-face-front,
.flippable-face-back {
position: absolute;
width: 100%;
height: 100%;
}
.flippable-faces {
-webkit-transform-style: preserve-3d;
-webkit-transition: 600ms;
}
.flippable-face-front,
.flippable-face-back {
position: absolute;
width: 100%;
height: 100%;
line-height: 10rem;
text-align: center;
-webkit-box-shadow: 0 0 1rem gray;
-webkit-backface-visibility: hidden;
}
.flippable-face-front {
color: black;
background-color: white;
}
.flippable-face-back {
color: white;
background-color: black;
-webkit-transform: rotateY(180deg);
}
.flippable input[type="checkbox"]:checked ~ .flippable-faces {
-webkit-transform: rotateY(180deg);
}
It appears that repositioning your divs fixes the issue. I don't have an answer as to why that was happening though. Sorry. Working Example | Example for iPhone
<div class="flippable">
<input id="flippable-trigger" type="checkbox" >
<label for="flippable-trigger" class="flippable-faces">
<div class="flippable-face-back">
Back
</div>
<div class="flippable-face-front">
Front
</div>
</label>
</input>
</div>
Page A has an iframe (that loads Page B). That Page B has a div#OutputDiv. My goal is to make that div in that iframe scrollable.
SOLUTION (CREDIT TO STEVE!):
Include overflow: auto for that div. However you must specify height too. Simply give any fixed value. eg height: 0.
Use a javascript function to make the div's height always same as the window's, even after window resize. height is now not fixed.
Code:
#outputDiv {
font-size: 12px;
font-family: Arial;
margin-right: 1em;
overflow: auto;
overflow-x: hidden; (optional)
-webkit-overflow-scrolling: touch; (enable smooth scrolling on mobile)
height: 0; (omit-able)
}
$(window).resize(function(){
$("#outputDiv").css("height",0).css("height",$(this).height());
});
$(window).trigger("resize");
TL;DR Full story
Page A.html - has an iframe to load Page B. When on Page A, that div#OutputDiv in that iframe must be scrollable. Works fine on PC but not scrollable on iPad/Android. Page structure:
Page B.php - Left half div#OutputDiv, right half div#map-canvas containing Google Maps.
(Sidenote: I think the #map-canvas CSS is pretty unchangeable, for example changing something may cause the Maps to extend height beyond browser height, which is not what I want.)
Page A.html
<style type="text/css">
#title-banner {
position: fixed;
top: 0;
left: 0;
width: 100%;
}
#real-time-alert {
margin-top: 155px;
margin-left: 10px;
}
.tab-content {
border-left: 1px solid #ddd;
padding: 10px;
height: 100%;
}
#map {
height: 100%;
}
.nav-tabs {
margin-bottom: 0;
}
#panel {
position: fixed;
top: 120px;
right: 10px;
bottom: 10px;
left: 350px;
}
iframe {
width: 100%;
height: 100%;
}
</style>
<body>
<div id="title-banner" class="well"><h1>Real-time incident updates</h1></div>
<div id="real-time-alert">
DEMO:<br>
<a id="demolink" style="cursor: pointer; font-weight: bold;">22/11/2013, 0.32.18AM: 3.128268, 101.650656<br></a>
</div>
<div id="panel">
<ul class="nav nav-tabs" id="myTab">
<li class="active"><a data-toggle="tab" href="#map">Map</a></li>
<li><a data-toggle="tab" href="#message">Messages</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="map"><iframe seamless name="map-report"></iframe></div>
<div class="tab-pane" id="message"></div>
</div>
</div>
</body>
Page B.php
*for div#map-canvas, I had to do the code below, or else when I hover on the page, div#OutputDiv will disappear. This may be not important.
$("*").hover(function(){
$("#map-canvas").css("position","fixed"); });
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map-canvas {
height: 100%;
width: 50%;
}
#content-pane {
float:left;
width:48%;
padding-left: 2%;
}
#outputDiv {
font-size: 12px;
font-family: Arial;
margin-right: 1em;
}
</style>
<body>
<div id="content-pane">
<div class='well well-small' id="inputs" style="margin: 1em 1em 0 0">
<b>TESTING ONLY</b> <br>
<label for="originLat">Incident Site: </label><input type="text" id="originLat" style="width:6em;" />
<input type="text" id="originLng" style="width:6em;" />
<button type="button">Calculate distances</button>
</br>eg. 3.126547,101.657825
</div>
<div id="outputDiv"></div>
</div>
<div id="map-canvas" style="position: fixed; right: 1px;"></div>
</body>
I can't see any overflow controls specified in the CSS (apologies if I missed them).
Have you tried:
div#OutputDiv { overflow: auto; height: 200px; }
The height is just for testing purposes - but you could use Javascript to get the actual height and apply it using either raw javascript or jQuery.
A good example (including how to detect orientation changes if device goes portrait to landscape or similar) can be found on:
How do I get the new dimensions of an element *after* it resizes due to a screen orientation change?
I have a problem with a div that at the begin is fixed in the bottom-left corner. I need to do it draggable but when I use jquery to do it the bottom position remains and the size of the div changes.
You can see the behavior in this page: http://paraguasparados.com
The div css code is:
.fcp-cpanel{
position:fixed;
bottom:20px;
left:10px;
z-index: 99999;
padding: 5px;
color: #000;
text-align: left;
font-size: 11px;
background:url('../img/blueicons/background.jpg') repeat-x;
border:1px solid #000;
}
The jquery code is:
$jn("#fcp-cpanel").draggable({
containment:"body",
scroll: false,
opacity: 0.35
});
When in firebug I remove the 'bottom' css style it works like it should.
Thanks for any help.
The easiest solution to this is to add a width and height to your fixed draggable <div> to stop it from resizing on drag.
The problem is that you are making a fixed element draggable and so the bottom css attribute is messing it up when you start moving it. A fix for this is to create a container div that has the fixed css attributes and inside you can add the draggable element. Something like this:
css:
.fcp-cpanel-container{
position:fixed;
bottom: 10px;
left:10px;
}
.fcp-cpanel{
padding: 5px;
color: #000;
text-align: left;
font-size: 11px;
background:url('http://paraguasparados.com/modules/mod_friendchatppd/img/blueicons/background.jpg') repeat-x;
border:1px solid #000;
}
html:
<div class="fcp-cpanel-container">
<div class="draggable fcp-cpanel">
<p><b>Amigos Online</b>
<span id="onlusers" class="onlusers">0</span><span onclick="register()"><img title="Registrar" alt="Registrar" src="http://paraguasparados.com//modules/mod_friendchatppd/img/blueicons/visible.jpg"></span>
<span onclick="maximize()" id="fcp-micon">
<img title="Maximizar" alt="Maximizar" src="http://paraguasparados.com//modules/mod_friendchatppd/img/blueicons/max.jpeg">
<img style="display:none;" title="Minimizar" alt="Minimizar" src="http://paraguasparados.com//modules/mod_friendchatppd/img/blueicons/min.jpeg">
</span>
</p>
</div>
</div>
I set up a working example with your code here: http://jsfiddle.net/NdUNu/.
I tried this and it did what I wanted
$(function() {
$("#draggable").draggable({ containment: "window" });
});