CSS/HTML iphone puts some additional space around edges of background image position. how do i remove it? - iphone

Summary
I've created a box with CSS and HTML. It scales horizontally and vertically, and maintains a nice gradient background and rounded corners. It only uses a single PNG background image (with multiple sprites). It works in IE7+
I'm not using CSS3, because there are subtleties in the corners and borders that make that almost impossible to reproduce with CSS3 alone. Also, it has to work in IE7 and 8.
I've had success making it work in all browsers that it needs to, but the problem is the iphone
Demo
A working example here:
http://www.trevorsimonton.com/iosbg/index.html
At the bottom of that page, I have links to output in various devices and browsers. It also works great on my HTC Evo, but I don't have the ability to post a screenshot from that device.
The problem
For some reason, there seems to be some kind of padding or margin or border or something on around the background image of each div. I've posted screenshots of these at the above site, and a few at the bottom of this post.
This only appears on the iphone.
It works great on the latest releases of Chrome, Safari and Firefox.
It also works great in IE7, IE8 and IE9
User zoom is disabled, and the scale is locked at 1.0
The code
The box has complex markup to allow it to scale and show image borders in IE7+
The markup is like this:
HTML
<div class='ksrfasw'>
<div class='content-container'>
<!-- top and top-right corner -->
<div class='ksrfasw-top'><div> </div></div>
<!-- right shadow, stretches down right side -->
<div class='ksrfasw-rs'>
<!-- left shadow, stretches down left side -->
<div class='ksrfasw-ls'>
<!-- inner gradient -->
<div class="ksrfasw-tab-content">
<!-- inner padding -->
<div class="ksrfasw-tab-content-inner">
CONTENT -- FINALLY!
</div>
</div>
</div>
</div>
<!-- bottom and bottom-right corner -->
<div class='ksrfasw-bottom'><div> </div></div>
</div>
</div>
The background image of each key div is the same. "box.png" -- that
contains all the different "sprites" for the various parts of the
puzzle.
There's also a "brace" inside the box to make min-height work in IE7.
Yes this markup seems excessive... but it does work as expected in all
browsers. It's a totally scalable, rounded corner, gradient
x-browser box.
CSS:
.ksrfasw-top,
.ksrfasw-top div,
.ksrfasw-ls,
.ksrfasw-rs,
.ksrfasw-bottom,
.ksrfasw-bottom div,
.ksrfasw-tab
{
background-image:url("box.png");
background-repeat:no-repeat;
padding:0px;
margin:0px;
border:0px;
outline:0px;
width:100%;
background-size:725px 1120px;
}
.ksrfasw-top div
{
background-position:0px -40px;
}
.ksrfasw-top
{
background-position:100% -60px;
padding-right:12px;
}
.ksrfasw-rs
{
background-position:100% -600px;
padding-right:12px;
}
.ksrfasw-ls
{
background-position:0 -100px;
}
.ksrfasw-bottom div
{
background-position:0px -20px;
}
.ksrfasw-bottom
{
background-position:100% 0px;
padding-right:12px;
}
.ksrfasw-brace
{
height:190px;
float:right;
width:1px;
}
.ksrfasw,
.ksrfasw-content-container
{
position:relative;
}
.ksrfasw-tabbed
{
padding-top:34px;
}
.ksrfasw-content-container
{
z-index:5;
}
.ksrfasw-tab
{
position:absolute;
width:154px;
display:block;
text-decoration:none;
height:61px;
top:0px;
}
.ksrfasw-tab-location
{
left:1px;
}
.ksrfasw-tab-name
{
left:151px;
}
.ksrfasw-tab-active
{
z-index:10;
background-position:-515px -700px;
}
.ksrfasw-tab-active-first .ksrfasw-tab-active
{
background-position:-515px -780px;
}
.ksrfasw-tab-active-first .ksrfasw-top div
{
background-position:5px -40px;
}
.ksrfasw-tab-inactive
{
z-index:1;
background-position:-515px -620px;
}
.ksrfasw-tab-content-inner
{
padding:20px 25px;
}
body
{
text-align:center;
}
#wrapper
{
width:95%;
max-width:700px;
min-width:300px;
margin:0 auto;
}
/**
* Markup free clearing.
*
* #see http://perishablepress.com/press/2009/12/06/new-clearfix-hack
*/
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
/* IE6 */
* html .clearfix {
height: 1%;
}
/* IE7 */
*:first-child + html .clearfix {
min-height: 1%;
}
.clearfix:after {
font-size: 0;
}
(Note: there are other things going on in the CSS and HTML to create tabs over the box... don't worry about that. in the example i have 1 box with tabs, and another without. both exibit the same behaviour)
iPhone Screenshots showing problem
Here is one:
and a zoomed version of the mysterious "padding"
iPad screenshot showing expectation
here's a rendering by ipad, working as expected:
I've tried all i can with background-position, position, top, left, margin, padding, border and even background-size properties, and although it works great on every device tested, (including ipad!) these lines just won't go away on iphone.
Is there something about iphone that spaces background images that I can prevent??
thanks, let me know if more examples or explanation of the linked example are necessary.

its the image. if you zoom in any browser, you see the same lines as on the iphone.
i think it comes from the retina-display, doubling all pixels.
you can make a proper image at double size and set it with an media query like
#media only screen and (-webkit-min-device-pixel-ratio: 2) {
.ksrfasw-top,.ksrfasw-top div,.ksrfasw-ls,.ksrfasw-rs,
.ksrfasw-bottom,.ksrfasw-bottom,div,.ksrfasw-tab{
background-image:url("box-doublesize.png");
}
this should fix your issue.

Related

Modal for fullsize image with gatsby-image - limit height and width

What I want to achive
I am using gatsby and want to design an image gallery. Clicking on one of the images shall open a modal, which: (1) is showing the image in maximum possible size, so that it still fits into the screen and (2) is centered in the screen.
My Code
/* imagemodal.js */
import React from 'react'
import * as ImagemodalStyles from './imagemodal.module.css'
import { Modal } from 'react-bootstrap'
import Img from 'gatsby-image'
import { useStaticQuery, graphql } from 'gatsby'
export default function Imagemodal() {
const data = useStaticQuery(graphql`
query {
file(relativePath: { eq: "images/mytestimage.jpg" }) {
childImageSharp {
fluid(maxWidth: 1200) {
...GatsbyImageSharpFluid
}
}
}
}
`)
return (
<div>
<Modal
show={true}
centered
className={ImagemodalStyles.imageModal}
dialogClassName={ImagemodalStyles.imageModalDialog}
onHide={(e) => console.log(e)}
>
<Modal.Header closeButton />
<Modal.Body className={ImagemodalStyles.imageModalBody}>
<h1>TestInhalt</h1>
<Img fluid={data.file.childImageSharp.fluid} />
</Modal.Body>
</Modal>
</div>
)
}
/* imagemodal.module.scss */
.imageModalDialog {
display: inline-block;
width: auto;
}
.imageModal {
text-align: center;
}
.imageModalBody img {
max-height: calc(100vh - 225px);
}
The Problem
The image does not scale to the screen size. The image is either too big - so it flows over the vieport - or it is too small. Secondly, the modal size does not respond to the image size correctly and / or is not centered.
What I tried
I used this suggestion for the CSS: How to limit the height of the modal?
I tried as well dozens of other CSS parameter combinations. But I could not find a working solution.
I tried to format the gatsby-image directly with a style-tag.
I tried as well react-modal but had similar problems.
Does anyone have a good solution to show a gatsby-image in full screen size in a responsive modal? For me it is okay to use either the bootstrap-modal or react-modal - or any other suitable solution.
Edit
In the end I ended up with a workaround. I used react-image-lightbox and took the Image-Source from gatsby-image as the input for lightbox. My component gets the data from the graphQL query in the props via props.imageData.
This works quite well for me:
import Lightbox from 'react-image-lightbox';
...
export default function Imagegallery(props) {
...
const allImages = props.imageData.edges
const [indexImageToShow, setIndexImageToShow] = useState()
...
return(
<Lightbox
mainSrc={allImages[indexImageToShow].node.childrenImageSharp[0].fluid.src}
...
/>
Special thanks to #FerranBuireu to point me to the right direction
Assuming that the functionality works as expected, as it seems, it's a matter of CSS rules, not React/Gatsby issue. The following rule:
.imageModalBody img {
max-height: calc(100vh - 225px);
}
It Will never be applied properly, since gatsby-image creates an output of HTML structure of nested <div>, <picture> and <img> so your rule will be affected by the inherited and relativity of the HTML structure. In other words, you are not pointing to the image itself with that rule because of the result HTML structure.
You should point to the <Img>, which indeed, it's a wrapper, not an <img>.
return (
<div>
<Modal show={true} onHide={handleClose} centered className={ImagemodalStyles.imageModal} dialogClassName={ImagemodalStyles.imageModalDialog}>
<Modal.Header closeButton />
<Modal.Body>
<Img className={ImagemodalStyles.imageModalBody} fluid={props.data.file.childImageSharp.fluid} />
</Modal.Body>
</Modal>
</div>
)
The snippet above will add the (spot the difference, without img):
.imageModalBody {
max-height: calc(100vh - 225px);
}
To the wrapper, which may or may not fix the issue, but at least will apply the rule correctly. It's difficult to know what's wrong without a CodeSandbox but you will apply the styles correctly with this workaround.
Keep always in mind that when using gatsby-image, the <img> it's profound in the resultant HTML structure so your styles should apply to the outer wrapper of it.

Ionic 5 Modal over modal is missing ion-backdrop

Why is my ion-backdrop + modal shadow styling not working when I open a modal on top of another modal?
PREFACE: This was working fine with V4, but broken on the upgrade to V5. I don’t want to change my page approach, just fix the CSS/whatever is actually causing the issue below.
My app opens a modal page with custom css to make it full screen.
I can then open another normal modal (but not full screen) over the
top. This 2nd modal is missing the ion-backdrop and its border shadow
styling.
I can see the ion-backdrop is definitely in the DOM, but it’s
obviously not showing.
Step1 Fine
enter image description here
Step 2 - broken ion-backdrop:
enter image description here
Showing my custom modal:
async showClipboard() {
const modal = await this._ModalController.create({
component: ClipboardPage,
cssClass: 'custom-round-modal',
componentProps: {
user: this.user
},
showBackdrop: true
});
await modal.present();
}
The CSS:
#media only screen and (min-width: 768px) {
.custom-round-modal {
.modal-wrapper {
border-radius: 15px !important;
-moz-border-radius: 15px !important;
-webkit-border-radius: 15px !important;
.ion-page {
border-radius: 15px !important;
-moz-border-radius: 15px !important;
-webkit-border-radius: 15px !important;
}
}
}
}
First off, I think you pasted the same screenshot twice by mistake. But I'm having the same issue, so I know what you mean.
It looks like Ionic 5 introduced this css for the modals:
.sc-ion-modal-ios-h:first-of-type {
--backdrop-opacity: var(--ion-backdrop-opacity, 0.4);
}
Which means when you show multiple modals at the same time, only the first one will get the backdrop.
A possible workaround is to add the backdrop yourself to your global css using something like this:
ion-modal {
--backdrop-opacity: var(--ion-backdrop-opacity, 0.4);
}
Or use the css class Ionic is using (but note that this one is iOS specific, so you'd likely need to do the same with the Android-equivalent class):
.sc-ion-modal-ios-h {
--backdrop-opacity: var(--ion-backdrop-opacity, 0.4);
}
NOTE: This will likely not look good if you are showing multiple modals on top of each other that are not fullscreen, since you'll be getting multiple backdrops on top of each other (so they'll get increasingly darker). But since your issue is a non-fullscreen modal on top of a fullscreen one, I think it will work in your case.
Hopefully the Ionic team will come up with a more elegant solution to this issue.
Thank you krisloekkegaard for your code, that helped me really out.
I want to add that it will only work if placed in the global sass or css files! You cannot do that from a component's style-file, because the modal will be created outside of it.
The following lines are a bit more precise, because they will activate the backdrop only on the last modal. Even if you have 10 stacked modals, there will be only the backdrop of the first and the backdrop of the last element overlaying each other.
.sc-ion-modal-md-h:last-of-type {
--backdrop-opacity: var(--ion-backdrop-opacity, 0.32);
}
.sc-ion-modal-ios-h:last-of-type {
--backdrop-opacity: var(--ion-backdrop-opacity, 0.32);
}
This is addressed now in the Ionic Documentation.
Please see under 'Customization' section for ion-modal : https://ionicframework.com/docs/api/modal
Add the following CSS to your modal class -
ion-modal.stack-modal {
--box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
--backdrop-opacity: var(--ion-backdrop-opacity, 0.32);
}
I solved the issue adding the following css into variables.css file in Ionic v5. Give a chance.
.backdrop-no-scroll {
ion-router-outlet {
background: white;
}

Fixed Responsive Top Nav / Off Canvas Nav with Single DOM Element

Let's get the fiddles out of the way first (built on the Foundation responsive framework):
Fiddle 1: one nav element, but becomes unfixed when side nav slides out
Fiddle 2: working but with multiple nav elments
Okay so, I have been racking my brain trying to develop and elegant solution for the following:
1) Make a responsive, fixed navigation that switches from stretching across the top to sliding out of the side on smaller screen sizes (ala the Facebook app)
2) I'd like to use the same DOM element for the navigation, rather than have two separate but identical elements
I was able to accomplish this using CSS translations, except for the fact that translations remove the fixed property of the nav (see fiddle 1).
The Fiddle 1 solution uses CSS translations like so:
-webkit-transform: translate3d(250px, 0, 0);
-moz-transform: translate3d(250px, 0, 0);
-o-transform: translate3d(250px, 0, 0);
transform: translate3d(250px, 0, 0);
While Fiddle 2 acts on the left and right margins of the content:
margin-right: -250px;
margin-left: 250px;
I'd like to somehow find a way to use just one DOM element for both elegance and so nav-related plugins will still work (like scrollspy)
One solution would be to give page position:absolute and change the left positioning instead transforming it.
.page {
transition:.3s ease-in-out;
position:absolute;
left:0px;
top:0px;
}
.page.navigating {
left:250px;
}
.page.navigating .top-bar .top-bar-section {
left:0px;
}
Demo here
EDIT
To make the nave be horizontal on small screen, you'll need to use #media queries. Something like this approximates the result you want
#media all and (max-width: 310px) {
.left li {
display:inline-block;
}
.left li a {
}
section.top-bar-section {
width:auto;
}
.left li:nth-child(odd) {
display:none;
}
.left li:nth-child(even) a {
display:inline-block;
width:auto;
padding:5px;
font-size: 50%;
background:black;
}
.page.navigating .top-bar .top-bar-section {
left:40px;
}
.page.navigating {
left:0px;
}
.name h1 {
float:right;
font-size:50%;
}
}
Updated Demo
I would suggest moving the element, outside of the div#page. That way any styling you put on the page won't affect it (including the translations), and you are free to style your nav list as needed.
http://jsfiddle.net/mKAtM/3/
This was just a quick test, i've moved the nav out of the div as suggested and added styles along the lines of:
.top-bar {
z-index:1000;
}
.top-bar.expanded{
-webkit-transform: translate3d(250px, 0, 0);
-moz-transform: translate3d(250px, 0, 0);
-o-transform: translate3d(250px, 0, 0);
transform: translate3d(250px, 0, 0);
overflow:visible;
}
(Think the overflow:visible is a different issue)
Obviously you need to add your transitions etc. and the translates should be in a class, but hope this is a step in the right direction
EDIT
updated fiddle to fix animation: http://jsfiddle.net/mKAtM/8/
css needs some tidying up, much easier to with your less/scss if you are using

CSS3 animation every time class is applied (Firefox bug?)

There is some problem with CSS3 native animation I've bumped into with Firefox (tried in v17) while Chrome is ok.
The sample is also available on Codepen:
http://codepen.io/anon/pen/yxteC
The code is also duplicated below.
I apply some class to some element (tried to apply that with JS on hovering, but hovering by itself works absolutely the same way (:hover selector instead of .hover class)).
So, the problem is that in Firefox the animation triggers only once: the first time the class had been applied. Any next time it does not.
That works perfectly in Chrome. I did not test any other browsers though (IE still does not widely support that, and Opera... well, it does not bother me much for now).
One more detail: if not to hide/show internal element (display:none/block), then it works ok in Firefox (but that's obviously not a solution).
I would really ask not to add any comments related to general cleanliness and possible improvements of the code. That's just an example.
HTML:
<div>
<span>menu</span>
<ul>
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
</ul>
</div>
CSS:
ul
{
display: none;
}
div.hover ul
{
display: block;
}
div li
{
position: relative;
top: -10px;
}
div.hover li
{
-webkit-animation: filterAppear 0.5s;
-moz-animation: filterAppear 0.5s;
top: 0;
opacity: 1;
-webkit-animation: filterItemAppear 0.1s;
-moz-animation: filterItemAppear 0.1s;
-webkit-animation-fill-mode: backwards;
-moz-animation-fill-mode: backwards;
}
div.hover li:nth-child(1)
{
-webkit-animation-delay: 0.15s;
-moz-animation-delay: 0.15s;
}
div.hover li:nth-child(2)
{
-webkit-animation-delay: 0.35s;
-moz-animation-delay: 0.35s;
}
div.hover li:nth-child(3)
{
-webkit-animation-delay: 0.55s;
-moz-animation-delay: 0.55s;
}
#-webkit-keyframes filterItemAppear
{
from { opacity:0; top:-25px; }
to { opacity:1; top:0; }
}
#-moz-keyframes filterItemAppear
{
from { opacity:0; top:-25px; }
to { opacity:1; top:0; }
}
I had similar problem and today I'll find the solution.
Firefox must notice the DOM manipulation somehow. So we must add .width() or setTimeout. Width solution is cleaner IMO.
Look at my edited CodePen for your example http://cdpn.io/yhbfB.
(More about it at http://css-tricks.com/restart-css-animation/)

position: fixed doesn't work on iPad and iPhone

I have been struggling with fixed positioning in iPad for a while. I know iScroll and it does not always seem to work (even in their demo). I also know that Sencha has a fix for that, but I couldn't Ctrl + F the source code for that fix.
I am hoping that someone may have the solution. The problem is that fixed positioned elements do not get updated when the user pans down/up on an iOS powered mobile Safari.
A lot of mobile browsers deliberately do not support position:fixed; on the grounds that fixed elements could get in the way on a small screen.
The Quirksmode.org site has a very good blog post that explains the problem: http://www.quirksmode.org/blog/archives/2010/12/the_fifth_posit.html
Also see this page for a compatibility chart showing which mobile browsers support position:fixed;: http://www.quirksmode.org/m/css.html
(but note that the mobile browser world is moving very quickly, so tables like this may not stay up-to-date for long!)
Update:
iOS 5 and Android 4 are both reported to have position:fixed support now.
I tested iOS 5 myself in an Apple store today and can confirm that it does work with position fixed. There are issues with zooming in and panning around a fixed element though.
I found this compatibility table far more up to date and useful than the quirksmode one:
http://caniuse.com/#search=fixed
It has up to date info on Android, Opera (mini and mobile) & iOS.
Fixed positioning doesn't work on iOS like it does on computers.
Imagine you have a sheet of paper (the webpage) under a magnifying glass(the viewport), if you move the magnifying glass and your eye, you see a different part of the page. This is how iOS works.
Now there is a sheet of clear plastic with a word on it, this sheet of plastic stays stationary no matter what (the position:fixed elements). So when you move the magnifying glass the fixed element appears to move.
Alternatively, instead of moving the magnifying glass, you move the paper (the webpage), keeping the sheet of plastic and magnifying glass still. In this case the word on the sheet of plastic will appear to stay fixed, and the rest of the content will appear to move (because it actually is) This is a traditional desktop browser.
So in iOS the viewport moves, in a traditional browser the webpage moves. In both cases the fixed elements stay still in reality; although on iOS the fixed elements appear to move.
The way to get around this, is to follow the last few paragraphs in this article
(basically disable scrolling altogether, have the content in a separate scrollable div (see the blue box at the top of the linked article), and the fixed element positioned absolutely)
"position:fixed" now works as you'd expect in iOS5.
position: fixed does work on android/iphone for vertical scrolling. But you need to make sure your meta tags are fully set. e.g
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
Also if you're planning on having the same page work on android pre 4.0, you need to set the top position also, or a small margin will be added for some reason.
I had this problem on Safari (iOS 10.3.3) - the browser was not redrawing until the touchend event fired. Fixed elements did not appear or were cut off.
The trick for me was adding transform: translate3d(0,0,0); to my fixed position element.
.fixed-position-on-mobile {
position: fixed;
transform: translate3d(0,0,0);
}
EDIT - I now know why the transform fixes the issue: hardware-acceleration. Adding the 3D transformation triggers the GPU acceleration making for a smooth transition. For more on hardware-acceleration checkout this article: http://blog.teamtreehouse.com/increase-your-sites-performance-with-hardware-accelerated-css.
now apple support that
overflow:hidden;
-webkit-overflow-scrolling:touch;
Fixed Footer (here with jQuery):
if (navigator.platform == 'iPad' || navigator.platform == 'iPhone' || navigator.platform == 'iPod' || navigator.platform == 'Linux armv6l') {
window.ontouchstart = function() {
$("#fixedDiv").css("display", "none");
}
window.onscroll = function() {
// 45 is the height of the Footer
var iPadPosition = window.innerHeight + window.pageYOffset-45;
$("#fixedDiv").css("position", "absolute");
$("#fixedDiv").css("top", iPadPosition);
$("#fixedDiv").css("display", "block");
}
}
In the CSS file should stand:
#fixedDiv {
position: fixed;
bottom: 0;
height: 45px;
...
}
Avoid on the same box using transform:--- and position:fixed. Element will stay in position:static if there is any transform.
I ended up using the new jQuery Mobile v1.1: http://jquerymobile.com/blog/2012/04/13/announcing-jquery-mobile-1-1-0/
We now have a solid re-write that provides true fixed toolbars on the
a lot of popular platforms and safely falls back to static toolbar
positioning in other browsers.
The coolest part about this approach is that, unlike JS-based
solutions that impose the unnatural scrolling physics across all
platforms, our scrolling feels 100% native because it is. This means
that scrolling feels right everywhere and works with touch, mousewheel
and keyboard user input. As a bonus, our CSS-based solution is super
lightweight and doesn’t impact compatibility or accessibility.
using jquery i am able to come up with this. it doesnt scroll smooth, but it does the trick. you can scroll down, and the fixed div pops up on top.
THE CSS
<style type="text/css">
.btn_cardDetailsPg {height:5px !important;margin-top:-20px;}
html, body {overflow-x:hidden;overflow-y:auto;}
#lockDiv {
background-color: #fff;
color: #000;
float:left;
-moz-box-shadow: 0px 4px 2px 2px #ccc;-webkit-box-shadow: 0px 4px 2px 2px #ccc;box-shadow:0px 4px 2px 2px #ccc;
}
#lockDiv.stick {
position: fixed;
top: 0;
z-index: 10000;
margin-left:0px;
}
</style>
THE HTML
<div id="lockSticky"></div>
<div id="lockDiv">fooo</div>
THE jQUERY
<script type="text/javascript">
function sticky_relocate() {
var window_top = $(window).scrollTop();
var div_top = $('#lockSticky').offset().top;
if (window_top > div_top)
$('#lockDiv').addClass('stick')
else
$('#lockDiv').removeClass('stick');
}
$(function() {
$(window).scroll(sticky_relocate);
sticky_relocate();
});
</script>
Finally we want to determine if the ipod touch in landscape or portrait mode to display accordingly
<script type="text/javascript">
if (navigator.userAgent.match(/like Mac OS X/i)) {
window.onscroll = function() {
if (window.innerWidth > window.innerHeight) {
//alert("landscape [ ]");
document.getElementById('lockDiv').style.top =
(window.pageYOffset + window.innerHeight - 268) + 'px';
}
if (window.innerHeight > window.innerWidth) {
//alert("portrait ||");
document.getElementById('lockDiv').style.top =
(window.pageYOffset + window.innerHeight - 418) + 'px';
}
};
}
</script>
The simple way to fix this problem just types transform property for your element. and it will be fixed.
.classname{
position: fixed;
transform: translate3d(0,0,0);
}
Also you can try his way as well this is also work fine.
.classname {
position: -webkit-sticky;
}
Even though the CSS attribute {position:fixed;} seems (mostly) working on newer iOS devices, it is possible to have the device quirk and fallback to {position:relative;} on occasion and without cause or reason. Usually clearing the cache will help, until something happens and the quirk happens again.
Specifically, from Apple itself Preparing Your Web Content for iPad:
Safari on iPad and Safari on iPhone do not have resizable windows. In
Safari on iPhone and iPad, the window size is set to the size of the
screen (minus Safari user interface controls), and cannot be changed
by the user. To move around a webpage, the user changes the zoom level
and position of the viewport as they double tap or pinch to zoom in or
out, or by touching and dragging to pan the page. As a user changes
the zoom level and position of the viewport they are doing so within a
viewable content area of fixed size (that is, the window). This means
that webpage elements that have their position "fixed" to the viewport
can end up outside the viewable content area, offscreen.
What is ironic, Android devices do not seem to have this issue. Also it is entirely possible to use {position:absolute;} when in reference to the body tag and not have any issues.
I found the root cause of this quirk; that it is the scroll event not playing nice when used in conjunction with the HTML or BODY tag. Sometimes it does not like to fire the event, or you will have to wait until the scroll swing event is finished to receive the event. Specifically, the viewport is re-drawn at the end of this event and fixed elements can be re-positioned somewhere else in the viewport.
So this is what I do: (avoid using the viewport, and stick with the DOM!)
<html>
<style>
.fixed{
position:fixed;
/*you can set your other static attributes here too*/
/*like height and width, margin, etc.*/
}
.scrollableDiv{
position:relative;
overflow-y:scroll;
/*all children will scroll within this like the body normally would.*/
}
.viewportSizedBody{
position:relative;
overflow:hidden;
/*this will prevent the body page itself from scrolling.*/
}
</style>
<body class="viewportSizedBody">
<div id="myFixedContainer" class="fixed">
This part is fixed.
</div>
<div id="myScrollableBody" class="scrollableDiv">
This part is scrollable.
</div>
</body>
<script type="text/javascript" src="{your path to jquery}/jquery-1.7.2.min.js"></script>
<script>
var theViewportHeight=$(window).height();
$('.viewportSizedBody').css('height',theViewportHeight);
$('#myScrollableBody').css('height',theViewportHeight);
</script>
</html>
In essence this will cause the BODY to be the size of the viewport and non-scrollable. The scrollable DIV nested inside will scroll as the BODY normally would (minus the swing effect, so the scrolling does stop on touchend.) The fixed DIV stays fixed without interference.
As a side note, a high z-index value on the fixed DIV is important to keep the scrollable DIV appear to be behind it. I normally add in window resize and scroll events also for cross-browser and alternate screen resolution compatibility.
If all else fails, the above code will also work with both the fixed and scrollable DIVs set to {position:absolute;}.
In my case, it was because the fixed element was being shown by using an animation. As stated in this link:
in Safari 9.1, having a position:fixed-element inside an animated element, may cause the position:fixed-element to not appear.
Had the same issue on Iphone X. To fixed it I just add height to the container
top: 0;
height: 200px;
position: fixed;
I just added top:0 because i need my div to stay at top
This might not be applicable to all scenarios, but I found that the position: sticky (same thing with position: fixed) only works on old iPhones when the scrolling container is not the body, but inside something else.
Example pseudo html:
body <- scrollbar
relative div
sticky div
The sticky div will be sticky on desktop browsers, but with certain devices, tested with: Chromium: dev tools: device emultation: iPhone 6/7/8, and with Android 4 Firefox, it will not.
What will work, however, is
body
div overflow=auto <- scrollbar
relative div
sticky div
This seems to work for Ionic5 on iPhone 6 Plus on iOS 12.4.2
.large_player {
float: left;
bottom: 0;
width: 100%;
position: fixed;
background-color: white;
border-top: black 1px solid;
height: 14rem;
z-index: 100;
transform: translate3d(0,0,0);
}
The transform tag makes it work, but it also seems a little clunky in how the scroll works, it is seems to redraw the 'on top' element after it's all moved and sort of resets and makes it jump a little.
Or, you could also use this tag option as well, position: -webkit-sticky;, but then you won't get, or may run in to trouble with WPA/browser or Android builds while having to do version checking and have multiple CSS tags.
.large_player {
float: left;
bottom: 0;
width: 100%;
position: -webkit-sticky;
background-color: white;
border-top: black 1px solid;
height: 14rem;
z-index: 100;
}
I don't know at what point it was fixed, but later iOS phones work without the transform tag. I don't know if it's the iOS version, or the phone.
As most iOS devices are usually on the most recent iOS version, it's pretty safe with go with a weird work around - such as using the transform tag, rather than building in a quirky detection routine for the sake of less than 1% of users.
Update:
After thinking about this answer further, this is just another way of doing this by platform for ionic5+:
.TS
import {Platform } from '#ionic/angular';
constructor(public platform: Platform) {
// This next bit is so that the CSS is shown correctly for each platform
platform.ready().then(() => {
if (this.platform.is('android')) {
console.log("running on Android device!");
this.css_iOS = false;
}
if (this.platform.is('ios')) {
console.log("running on iOS device!");
this.css_iOS = true;
}
if (this.platform.is('ipad')) {
console.log("running on iOS device!");
this.css_iOS = true;
}
});
}
css_iOS: boolean = false;
.HTML
<style *ngIf="css_iOS">
.small_player {
position: -webkit-sticky !important;
}
.large_player {
position: -webkit-sticky !important;
}
</style>
<style>
.small_player {
float: left;
bottom: 0;
width: 100%;
position: fixed;
background-color: white;
border-top: black 1px solid;
height: 4rem;
z-index: 100;
/*transform: translate3d(0,0,0);*/
}
.large_player {
float: left;
bottom: 0;
width: 100%;
position: fixed;
background-color: white;
border-top: black 1px solid;
height: 14rem;
z-index: 100;
/*transform: translate3d(0,0,0);*/
}
</style>