How to access the real 100vh on iOS in CSS - ios

This is a self Q&A
If you've ever tried to use 100vh in CSS on iOS you will have found that it isn't actually 100vh when the browser chrome is expanded. It's a well documented bug that Apple decided was actually a feature! This is a good read to explain the bug.
So what is the best way to get around this "feature"? Ideally the answer requires no JavaScript (but that seems unlikely), should be clean, not require a bunch of inline styles, and ideally can be opted into in CSS (sometimes you might want the default 100vh).

Set a root CSS var like so in your stylesheet:
// CSS vars
:root {
--real100vh: 100vh;
}
Then in JavaScript, on load (or jQuery ready event) and on also on resize, you want to run this code:
set100vhVar() {
// If less than most tablets, set CSS var to window height.
let value = "100vh"
// If window size is iPad or smaller, then use JS to set screen height.
if (window.innerWidth && window.innerWidth <= 1024) {
value = `${window.innerHeight}px`
}
document.documentElement.style.setProperty("--real100vh", value)
}
Now you can simply use the CSS: height: var(--real100vh); wherever you want 100vh to actually be the real 100vh on mobile, and this will simply work!
It looks better if you also add a transition: height 0.4s ease-in-out; on the same element, so it doesn't snap when you scroll down on mobile.
The advantage of using a CSS var to do this is that you can override this whenever you like, for example you might want certain breakpoints to be height: 500px, and this is hard to do if you use an inline style. You can also use this inside calc(), like height: calc(var(real100vh) - 100px); which is useful for fixed headers.
If you use Vue/Nuxt, take a look at how we have implemented that here.
UPDATE IN DEC 2022
You can achieve this without JS now, using CSS vars and media queries. Like so:
:root {
--unit-100vh: 100vh;
}
#supports (height: 100dvh) {
:root {
--unit-100vh: 100dvh;
}
}

Depending on the needed browser support, the newest iteration of relative viewport units, for example dvh (dynamic viewport height) might be an option too.
When you want the viewport to be automatically sized in response to browser interfaces dynamically expanding or retracting, you can use the dynamic viewport size. The dynamic viewport size allows the content you design to fit exactly within the viewport, irrespective of the presence of dynamic browser interfaces.

CSS Grid is the solution.
.grid-container {
height: 100vh;
grid-template-columns: 1fr;
grid-template-rows: 30px 1fr 30px
}

Related

Anchor links in HTML file don't work in iframe after iOS fix

Ok, so I am working on a javascript application. One feature is a help page for the application. The way I am trying to do it is to have a button that opens the help page - .html - in an iframe contained within a container div.
This works just fine, but I run into the well-known issue of iframes not scrolling in iOS(i.e. on iPads and iPhones).
There is a common fix for this, which involves setting overflow rules in the css for the container div.
So the initial CSS is something like:
#iframeContainer {
position:absolute;
left:0px;
top:0px;
width: 750px;
}
#iframeContainer iframe {
{
width:100%;
height: 600px;
}
and the css with the iOS fix is something like:
#iframeContainer {
position:absolute;
left:0px;
top:0px;
width: 750px;
height: 600px;
-webkit-overflow-scrolling: touch;
overflow: scroll;
}
#iframeContainer iframe {
{
width:100%;
height: 12000px;
}
The overflow rules are added to the css for the container, but in order to work, you have to set a height on the container. You also have to adjust the height of the iframe itself. If I leave it at its initial 600px, it never overflows the container div and there is no scrolling. If I don't set any height at all on the iframe, it hardly shows anything at all. So I have to set the iframe's height to contain all of the contents of the HTML file, which comes to 12000px.
All of this works, and the scrolling issue on iOS is fixed. But here's where I run into the issue in question.
The HTML page being loaded into the iframe has within it a bunch of anchor links that link to other places on the same page. After applying the iOS fix, those anchor links no longer work at all. Nothing happens when they're clicked.
I am reasonably sure that the reason is because when I set the iframe's height to 12000px, the HTML page behaves as though it is all displayed on one page, in which event, nothing happening is the appropriate behavior for anchor links.
So I think understand what is going on, and I'm just wondering if anyone has any ideas on how to make the anchor links work while keeping the iOS fix in tact. If I decrease the iframe's height to make the anchor links work, then less and less of the HTML page will show up within the iframe. If I remove the iOS fix all together, the anchor links will work but the scrolling won't work on iOS.
Open to anything. For the time being, I've abandoned the idea and the 'Help' button just opens the HTML page in a new tab/window.

CSS scale transformation on iOS Safari zooms page out

I'm trying to have a snippet of text "zoom & fade in" once the page is loaded. To do so, I'm creating a div with the text inside and setting it to transform immediately:
.whatIwantZoomed {
opacity:0;
/* Vendor Prefixes here */
transform:scale(4,4);
/* Vendor Prefixes here */
transition:transform 1s, opacity 1s;
}
Now, when called from my Javascript function, an animated class is applied which reduces the scale to (1,1):
.whatIwantZoomed.animated {
opacity:1;
/* Vendor Prefixes here */
transform:scale(1,1);
}
Now, on mobile Safari (both iOS 7 & iOS 8), the effect actually does work. The problem is the scaled text is actually larger than the width of the viewport, causing it to 'resize' and zoom the page out. As the animation occurs, the page resizes back to how it should be.
What I'm trying to do here is remove this unwanted viewport width alteration. I've tried setting the body to have a property of overflow-x:hidden; to no avail, and I can't seem to get the viewport metatag to help me either.
Can anyone shed some light on a solution here? Thanks.
EDIT: Added a fiddle demonstrating this. Notice the scrollbars in the HTML frame? That's what I'm trying to prevent.
Try this
DEMO
div {
text-align:center;
background-color:red;
transform-origin: 50% 50%;
transform:perspective(1200) scale(1);
animation:animated 1s ease-in-out;
}
#keyframes animated{
from{transform:scale(10);opacity:0}
}
For anyone coming across this, it seems to be related to this bug
The root cause is things that are off screen incorrectly trigger safari (or wkwebview) to resize the viewport.
Add this to your viewport meta tag:
shrink-to-fit=no

How do I remove or reduce the margins when printing from iPad safari using css?

I am trying to remove or at the very least reduce the page margins when printing a webpage from an iPad. I have attempted various forms of the #Page directive as indicated by MDN, but it has had no effect. Examples of attempts:
#page {
margin: 0.5cm;
}
Also:
#page
{
size: auto;
margin: 0mm;
}
body
{
margin: 0px;
}
I then proceeded to try to find some documentation of whether or not iOS safari supports the #page directive, but all I found was a SO question from 2009 that said safari in general doesn't support it, which to my understanding is no longer the case, and regular safari does in fact support it.
So, is it possible? Am I doing something wrong with #page that causes it to ignore margin? Or does safari for iPad simply ignore any attempts to change the margins via css?
Unfortunately, it looks like what you are trying to achieve is not possible.The Safari CSS Reference only lists basic support for Paged Media and is missing support for the size property. As a result, Safari (desktop and mobile) does not support applying margin or size properties within the #page rule.
I also did some additional testing with Safari Mobile for iOS 8 in regards to printing with the simulator. I was able to confirm that it is not possible to modify the paper margins or remove the print footer at this time.

Media queries and viewport width - good CSS fix doesn't work on iPad

There is well known problem with media query width, which is not the same as viewport width in some browsers (WebKit browsers change the size of their CSS viewport when scrollbars are visible). I wanted to fix the problem by moving the vertical scrollbar from body or html to first wrapper div (as described on stackoverflow: https://stackoverflow.com/a/10091608/1647291).
The fix
Here's the fix with CSS:
body, html { overflow: hidden; height: 100%; }
div.wrapper { overflow: auto; height: 100%; }
It moves the vertical scrollbar from body or html to the first div inside body. Thanks to that you don't need to worry about viewport widht in media queries.
The problem
But unfortunately this great method has one bad side effect - on iPad (and possibly on some other platforms too) page can't be scrolled smoothly. After you stop touching the screen it stops scrolling imediately, there's no smooth and slow easing.
This simple solution with CSS is much simpler and better than all those methodes with testing the viewport with javascript. Some of them are described here but they are not reliable or make the site works very slow:
CSS media queries and JavaScript window width do not match
http://github.com/tysonmatanich/viewportSize
http://github.com/ryanve/verge
Is there any way to use this CSS fix and make the iPad scroll correctly?
It is possible you are over thinking this. We make websites all day and this is not a problem. I think that you might be worrying too much about the specific px widths. If 680px vs 693px is a big deal, you are thinking about this the wrong way. I suggest you design mobile first and make a break point whenever it gets ugly (with ems). For sites with short pages and long pages, (causing the scrollbar to appear sometimes and jump between pages when there is no scrollbar) - to just add this and call it a day. Good luck!
html { overflow-y scroll }

jQuery Mobile background not full height

When I load my jQuery Mobile page on an iphone, some of the page extends out of the initial viewport. The space that is out of the initial viewport to begin with is white, not gray which it should be. I've attempted to set the height to 100% using this line of code: [data-role=page]{height: 100% !important; position:relative !important;} however this still does not do the trick.
I always have the same problem with my JQM pages. I use that to make my page height 100%:
$(document).delegate('#yourPage', 'pageshow', function () {
var the_height = ($(window).height() - $(this).find('[data-role="header"]').height() - $(this).find('[data-role="footer"]').height());
$(this).height($(window).height()).find('[data-role="content"]').height(the_height);
});
Hope this helps.
First, don't misuse !important. To diagnose what's wrong with the CSS, you can use Firebug in Firefox / Developer Console in Chrome. ( Safari & IE have similar things ). Some CSS may be overridden, or layers maybe overlapped.
Without your HTML codes & jQuery scripts, I can't really help on this, but normally, to make the content to full height, you have to set html CSS and body CSS to use height: 100%;.

Resources