iOS 7 iPad Safari Landscape innerHeight/outerHeight layout issue

CssIpadSafariIos7

Css Problem Overview


We're seeing issues with a web app that has a height of 100% on Safari in iOS 7. It appears that the window.innerHeight (672px) doesn't match window.outerHeight (692px), but only in landscape mode. What ends up happening is that in an app with 100% height on the body, you get 20px of extra space. This means that when a user swipes up on our app, the navigation elements get pulled behind the browser chrome. It also means that any absolutely positioned elements that are at the bottom of the screen end up being 20px off.

This issue was also outlined in this question here: https://stackoverflow.com/questions/18855642/ios-7-css-html-height-100-692px

And can be seen in this ambiguous screenshot: iOS 7 Safari outerHeight issue

What we're trying to do is hack around this so that until Apple fixes the bug, we don't have to worry about it.

One way of doing this is to absolutely position the body only in iOS 7, but this pretty much puts the extra 20px at the top of the page instead of the bottom:

body {
    position: absolute;
    bottom: 0;
    height: 672px !important;
}

Any help with forcing outerHeight to match innerHeight, or hacking around it so that our users can't see this issue would be much appreciated.

Css Solutions


Solution 1 - Css

In my case, the solution was to change positioning to fixed:

@media (orientation:landscape) {
	html.ipad.ios7 > body {
	    position: fixed;
	    bottom: 0;
	    width:100%;
	    height: 672px !important;
	}
}

I also used a script to detect iPad with iOS 7:

if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i)) {
	$('html').addClass('ipad ios7');
}

Solution 2 - Css

Simple, cleaner CSS-Only solution:

html {
     height: 100%;
     position: fixed;
     width: 100%;
   }

iOS 7 seems to set the height correctly with this. Also there is no need for resize javascript events, etc. Since you are working with a full height app, it doesn't really matter if it is always position fixed.

Solution 3 - Css

Samuel's answer, as also stated by Terry Thorsen, is working great, but fails in case the webpage has been added to the iOS home.

A more intuitive fix would be to check for window.navigator.standalone var.

if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i) && !window.navigator.standalone) {
	$('html').addClass('ipad ios7');
}

This way it only applies when opened inside Safari, and not if launched from home.

Solution 4 - Css

Samuel's answer is the best although it breaks if a user adds the page to their home screen (home screen pages don't exhibit the bug). Check the innerHeight before adding the class like so:

if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i)) {
    if(window.innerHeight==672){
        $('html').addClass('ipad ios7');
    }
}

Note that the bug also does not exhibit under webview.

Solution 5 - Css

I used this JavaScript solution for solving that problem:

    if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i) && window.innerHeight != document.documentElement.clientHeight) {
  var fixViewportHeight = function() {
    document.documentElement.style.height = window.innerHeight + "px";
    if (document.body.scrollTop !== 0) {
      window.scrollTo(0, 0);
    }
  }.bind(this);

  window.addEventListener("scroll", fixViewportHeight, false);
  window.addEventListener("orientationchange", fixViewportHeight, false);
  fixViewportHeight();

  document.body.style.webkitTransform = "translate3d(0,0,0)";
}

Solution 6 - Css

A variant of Samuel's approach, but with position: -webkit-sticky set on html worked for me the best.

@media (orientation:landscape) {
    html.ipad.ios7 {
        position: -webkit-sticky;
        top: 0;
        width: 100%;
        height: 672px !important;
    }
}

Notice 'top: 0', not 'bottom: 0', and target element is 'html', not 'body'

Solution 7 - Css

Basically there are two bugs - the hight of the window in landscape mode and the scroll position when the user rewerts to it from portrait mode. We have solved it this way:

the hight of the window is controlled by:

// window.innerHeight is not supported by IE
var winH = window.innerHeight ? window.innerHeight : $(window).height();

// set the hight of you app
$('#yourAppID').css('height', winH);

// scroll to top
window.scrollTo(0,0);

now, the above can be put into a function and bind to window resize and/or orientation change events. that's it... see example:

http://www.ajax-zoom.com/examples/example22.php

Solution 8 - Css

You need JavaScript to work around this bug. window.innerHeight has the correct height. Here's the simplest solution I can think of:

$(function() {
	function fixHeightOnIOS7() {
		var fixedHeight = Math.min(
			$(window).height(), // This is smaller on Desktop
			window.innerHeight || Infinity // This is smaller on iOS7
		);
		$('body').height(fixedHeight);
	}
	
	$(window).on('resize orientationchange', fixHeightOnIOS7);
	fixHeightOnIOS7();
});

You'll also need to set position: fixed on the <body>.

Here's a complete, working example:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8"/>
		<meta name="viewport" content="width=device-width, initial-scale=1"/>
		<meta name="apple-mobile-web-app-capable" content="yes"/>
		<title>iOS7 height bug fix</title>
		<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
		<script>
			$(function() {
				function fixHeightOnIOS7() {
					var fixedHeight = Math.min(
						$(window).height(),
						window.innerHeight || Infinity
					);
					$('body').height(fixedHeight);
				}
				
				$(window).on('resize orientationchange', fixHeightOnIOS7);
				fixHeightOnIOS7();
				
				// Generate content
				var contentHTML = $('#content').html();
				for (var i = 0; i < 8; i++) contentHTML += contentHTML;
				$('#content').html(contentHTML);
			});
		</script>
		<style>
			html,
			body
			{
				margin: 0;
				padding: 0;
				height: 100%;
				width: 100%;
				overflow: auto;
				position: fixed;
			}
			#page-wrapper
			{
				height: 100%;
				position: relative;
				background: #aaa;
			}
			#header,
			#footer
			{
				position: absolute;
				width: 100%;
				height: 30px;
				background-color: #666;
				color: #fff;
			}
			#footer
			{
				bottom: 0;
			}
			#content
			{
				position: absolute;
				width: 100%;
				top: 30px;
				bottom: 30px;
				overflow: auto;
				-webkit-overflow-scrolling: touch;
			}
		</style>
	</head>
	<body>
		<div id="page-wrapper">
			<div id="header">Header</div>
			<div id="content">
				<p>Lorem ipsum dolor sit amet.</p>
			</div>
			<div id="footer">Footer</div>
		</div>
	</body>
</html>

Solution 9 - Css

With reference to the accepted answer, I've also had luck with the following rule:

html.ipad.ios7 {
    position: fixed;
    width: 100%;
    height: 100%;
}

This has the added advantage in that it appears to stop the html element scrolling "under" a fixed body element.

Solution 10 - Css

If I use this:

if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i) && !window.navigator.standalone) {
    $('html').addClass('ipad ios7');
}

My Safari on Mac shows the same html classes... SO its not working correctly.

I tried to combine a few things - that worked for me, so I can manage it in the browser and without Browser view.

jQuery

if (navigator.userAgent.match(/iPad/i) && (window.orientation) ){
     $('html').addClass('ipad ');
	    if (window.innerHeight !=  window.outerHeight ){
		  $('html').addClass('browser  landscape');				 
	}
	else{
		 $('html').addClass('browser portrait');				   
	}
} 

CSS

@media (orientation:landscape) {
   html.ipad.browser > body {
       position: fixed;  
       height: 671px !important;
   }
}

///// With this you are more flexible or other OS and Browsers

Solution 11 - Css

I came across this page for the same issue. There are a lot of useful answers here, and others not (for me).

However, I found a solution, which works in my case, and works totally independent of which OS version and which bug now or in the past or future.

Explaination: Developping a web app (no native app) with several modules of fixed size in fullscreen, with class name "module"

.module {position:absolute; top:0; right:0; bottom:0; left:0;}

which contains a footer with class name "footer"

.module > .footer {position:absolute; right:0; bottom:0; left:0; height:90px;}

Nevermind, if I set the height of the footer later to another height, or even its height is set by its content, I can use this following code for correction:

function res_mod(){
	$('.module').css('bottom', 0); // <-- need to be reset before calculation
	var h = $('.module > .footer').height();
	var w = window.innerHeight;
	var o = $('.module > .footer').offset();
	var d = Math.floor(( w - o.top - h )*( -1 ));
	$('.module').css('bottom',d+'px'); // <--- this makes the correction
}

$(window).on('resize orientationchange', res_mod);

$(document).ready(function(){
	res_mod();
});

Thanks to the skills of Matteo Spinelli I can still use iScroll with no problems, as its change events fortunately are fired after. If not, it would be necessary to recall the iScroll-init again after the correction.

Hope this helps somebody

Solution 12 - Css

The accepted answer doesn't cope when the favorites bar is showing. Here is am improved catch all fix:

@media (orientation:landscape) {
  html.ipad.ios7 > body {
    position: fixed;
    height: calc(100vh - 20px);
    width:100%;
  }
}

Solution 13 - Css

what if you try

html{ bottom: 0;padding:0;margin:0}body {
position: absolute;
bottom: 0;
height: 672px !important;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionhisnameisjimmyView Question on Stackoverflow
Solution 1 - CssSamuel Moreno LópezView Answer on Stackoverflow
Solution 2 - CssmikeStoneView Answer on Stackoverflow
Solution 3 - CssAndrea TondoView Answer on Stackoverflow
Solution 4 - CssTerry ThorsenView Answer on Stackoverflow
Solution 5 - CssczuendorfView Answer on Stackoverflow
Solution 6 - CssovermailedView Answer on Stackoverflow
Solution 7 - CssVadimView Answer on Stackoverflow
Solution 8 - CssandraasparView Answer on Stackoverflow
Solution 9 - CssNick MaynardView Answer on Stackoverflow
Solution 10 - Cssuser3432605View Answer on Stackoverflow
Solution 11 - CssddlabView Answer on Stackoverflow
Solution 12 - CssNick HingstonView Answer on Stackoverflow
Solution 13 - CssainosView Answer on Stackoverflow