javascript max viewport height after orientation change Android & iOS
This is a simple solution that will append the browsers width and height to the document body on load and window resize.
jQuery.event.add(window, "load", resize);
jQuery.event.add(window, "resize", resize);
function resize()
{
var h = jQuery(window).height();
var w = jQuery(window).width();
jQuery("body").css({"width": w, "height": h});
}
Comments
-
Dan Kanze almost 2 years
The Goal:
To find the max viewport height of a device including the space of the
address bar
so that we can dynamically resize the min-body and push our content up.The Problem:
Mobile browsers handle orientation states differently and update DOM properties on orientation change differently.
Detect rotation of Android phone in the browser with JavaScript
With Android phones,
screen.width
orscreen.height
also updates as the device is rotated.|==============================================================================| | Device | Events Fired | orientation | innerWidth | screen.width | |==============================================================================| | iPad 2 | resize | 0 | 1024 | 768 | | (to landscape) | orientationchange | 90 | 1024 | 768 | |----------------+-------------------+-------------+------------+--------------| | iPad 2 | resize | 90 | 768 | 768 | | (to portrait) | orientationchange | 0 | 768 | 768 | |----------------+-------------------+-------------+------------+--------------| | iPhone 4 | resize | 0 | 480 | 320 | | (to landscape) | orientationchange | 90 | 480 | 320 | |----------------+-------------------+-------------+------------+--------------| | iPhone 4 | resize | 90 | 320 | 320 | | (to portrait) | orientationchange | 0 | 320 | 320 | |----------------+-------------------+-------------+------------+--------------| | Droid phone | orientationchange | 90 | 320 | 320 | | (to landscape) | resize | 90 | 569 | 569 | |----------------+-------------------+-------------+------------+--------------| | Droid phone | orientationchange | 0 | 569 | 569 | | (to portrait) | resize | 0 | 320 | 320 |
Because of this it is clear that to find the max viewport height no matter what orientation, using a single function to return the max height of a device will never be constant over a range of devices.
Other problems I have discovered that don't make these two play nice:
- The
window.devicePixelRatio
property can return inconsistent heights when dividing bywindow.outerHeight
. - Delay
window.setTimeout(function() {}, time)
needs to be used to give DOM elements a chance to update after orientation change. -
window.outerHeight
is not updated on orientation changes for iOS devices. Usingscreen.availHeight
as a fallback includes the bottom nav bar as total height. - Using a
#header
,#content
,#footer
structure forces you to dynamically recalculate the#content{min-height}
to push the#footer
down when thebody
is dyamically updated.
A Solution:
First let's take a look at DIV structure:
<style> #header,#content,#footer{width:100%;} </style> <body> <div id="header"></div> <div id="content"></div> <div id="footer"></div> </body>
We want to prevent devices from scaling on their own:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
We need help to have the ability to return a max viewport height and hide address bar for iOS:
<script src="iOS.js" type="text/javascript"></script>
Then detect if the device supports orientation change and use resize as a fallback:
var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/i) ? true : false); var android = (navigator.userAgent.match(/Android/i) ? true : false); var supportsOrientationChange = "onorientationchange" in window; var orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";
The belly of the beast:
function updateOrientation() { var orientation = (window.orientation); if(android) { window.setTimeout(function() { window.scrollTo(0,0); var size = window.outerHeight/window.devicePixelRatio; $('body').css('min-height', size + 'px'); var headerHeight = $('#header').height(); var footerHeight = $('#footer').height(); var contentHeight = size - (headerHeight+footerHeight); $('#content').css('min-height', contentHeight + 'px'); window.scrollTo(0,1); }, 200); } if(iOS) { window.setTimeout(function(){ window.scrollTo(0,0); var size = iOS_getViewportSize(); var headerHeight = $('#header').height(); var footerHeight = $('#footer').height(); var contentHeight = size.height - (headerHeight+footerHeight); $('#content').css('min-height', contentHeight + 'px'); window.scrollTo(0,1); }, 0); } }
Add event listeners for page load and orientation event:
if(iOS) { iOS_addEventListener(window, "load", iOS_handleWindowLoad); iOS_addEventListener(window, "orientationchange", iOS_handleOrientationChange); iOS_addEventListener(window, "resize", iOS_handleReize); } addEventListener("load", function() { updateOrientation(); }, false); addEventListener(orientationEvent, function() { updateOrientation(); }, false);
Proof is in the pudding:
iPhone 4 & 4s Portrait & Landscape
Android Portrait & Landscape
The goal here is to minify this solution or make it better.
- The
-
Dan Kanze over 11 yearsI see what you are doing here. Although, using if
(CurrentOrientation && CurrentOrientation !== NewOrientation)
is not allowing the ability for a user to pull height after orientation change in any state. For example, I view landscape I am returned 230px / I view portrait I am returned 450px. Is there a modification that you could make to this that would support that? -
frenchie over 11 yearsWell then it's an easy fix: what's the name of the function that's returning 230 and 450?
-
Dan Kanze over 11 yearsI suppose what I'm saying is that I need a function to return the viewport height on orientation change. For example, with an iphone, I would expect to be returned 230px at landscape, and 450px at portrait.
var h = (window.screen.availHeight/window.devicePixelRatio); alert(h);
-
frenchie over 11 yearsSee edit, just updated it with window.screen.availHeight/window.devicePixelRatio
-
Dan Kanze over 11 yearsI'm sorry but this doesn't properly calculate the max viewport height for either Android or iPhone.
-
frenchie over 11 yearsYou just put that (window.screen.availHeight/window.devicePixelRatio); returns 230px or 450px!! So I took your function and modified the code accordingly to make it work with that function. Anyway, when you get the function's name and syntax, just replace it with the line (window.screen.availHeight/window.devicePixelRatio); and it'll work. Happy coding.
-
frenchie over 11 yearsNote, I changed it to work with jQuery; if I were you, I'd try that and see what you get (assuming jQuery is already on your page).
-
Dan Kanze over 11 yearsHave you tried this yourself? I'm looking at this with both a iPhone and Android in front of me and it doesnt seem to return the results im looking for..I'm sorry if the question was unclear but im tyring to find the max viewport height of a device. The code I provided was mearly to provoke the idea of what I am trying to acheive. As mentioned above, the
window.screen.availHeight
does not work for iPhone. -
Dan Kanze over 11 yearsis this a "simulator" or an emulator? "simulators" will not properly replicate this problem so i am sorry about that.
-
frenchie over 11 yearsNo, I don't have an iPhone or Android to try it on. You are solving two issues: 1) determining the orientation's height and 2) detecting orientation changes. My solution does solve problem 2) and all you need to find is one line to get the value. Did you try with the jquery line?
-
Dawson over 11 yearsIt's the 'iOS Simulator' that came with my Mac
-
Dan Kanze over 11 yearsI wish it was this easy. The iPhone is buggy in updating DOM element properties after orientation change. The real problem is overcoming this obsticle. Testing with an iPhone in front of you seems like the only real way to replicate the issue I describe here. If the iPhone didn't have this issue I would also expect your logic to work.
-
Dan Kanze over 11 yearsDoes your iOS simulator invoke mobile safari with the same hardware constraints? Im sorry but simulators do not replicate this problem the way the actual device does.
-
frenchie over 11 yearsI just thought of something that could do the trick. At the top of the body, you put a div with no content; give it ID WidthCheck and CSS {clear: both; height: 1px; background: transparent;} This will draw a line that spans the whole width. And then, every second, we're going to check the width of this div: if it's over 350px wide then we're on landscape and if it's less then wouldn't that mean we're on portrait? I think that could solve it. All you'd need to do is check for the width of that div. See update.
-
Dan Kanze over 11 yearsYou are assuming the width of the portrait is equal to the height of the landscape correct?
-
Dawson over 11 yearsYes - Mobile Safari. It is the simulator that comes with Xcode, "the complete developer toolset for building Mac, iPhone, and iPad apps, including the Xcode IDE, Instruments, and iOS Simulator" <-- developer.apple.com/technologies/ios
-
frenchie over 11 yearsNo, if we're just looking to determine if we've changed orientation, we don't care about the height. If we can determine that the width changed, then wouldn't that mean that the height also changed, and that therefore the orientation changed?
-
BoltClock over 11 yearsIt does not come with the same hardware constraints, but it does respond correctly to media queries and other environment variables the same way an actual device does.
-
Dan Kanze over 11 yearsIt may respond the same but in testing the method does not return the correct height for each orientation.