Detect Orientation Change on Mobile Devices

By  on  

Unless your mobile application allows for only portrait or only landscape views, there's a good chance you will need to adjust a few things. Even if you've built your layouts in a fluid fashion, you may need to programmatically make some changes. There are a few strategies for knowing when pages have changed, so let's check out how we can detect orientation changes on mobile devices.

orientationchange Event

This method is what you would expect from a mobile API; a simple orientationchange event on the window:

// Listen for orientation changes
window.addEventListener("orientationchange", function() {
	// Announce the new orientation number
	alert(screen.orientation);
}, false);

During these changes, the window.orientation property may change. A value of 0 means portrait view, -90 means a the device is landscape rotated to the right, and 90 means the device is landscape rotated to the left.

resize Event

Some devices haven't provided the orientationchange event, but do fire the window's resize event:

// Listen for resize changes
window.addEventListener("resize", function() {
	// Get screen size (inner/outerWidth, inner/outerHeight)
	
}, false);

A bit less obvious than the orientationchange event, but works very well.

Screen Sizing

There are a few properties you can retrieve from the window object to get screen size and what I consider "virtual" screen size:

  • outerWidth, outerHeight: the real pixel real estate
  • innerWidth, innerHeight: the virtual pixel real estate

These don't give you the orientation, of course, but using some simple math, you can find out if the window is currently wider or taller.

Media Queries

We can identify orientation by CSS media queries as well:

/* portrait */
@media screen and (orientation:portrait) {
	/* portrait-specific styles */
}
/* landscape */
@media screen and (orientation:landscape) {
	/* landscape-specific styles */
}

If you'd like to get clever, you can code a periodical "watcher" with JavaScript to check the background color of a block and fire your own orientation change.

matchMedia

The native window.matchMedia method allows for live media-querying. We can use the media queries above to find out if we're in portrait or landscape view:

// Find matches
var mql = window.matchMedia("(orientation: portrait)");

// If there are matches, we're in portrait
if(mql.matches) {  
	// Portrait orientation
} else {  
	// Landscape orientation
}

// Add a media query change listener
mql.addListener(function(m) {
	if(m.matches) {
		// Changed to portrait
	}
	else {
		// Changed to landscape
	}
});

So there are a few ideas and options for you. I'd love to hear any more practical techniques you've used!

Recent Features

  • By
    9 Mind-Blowing WebGL Demos

    As much as developers now loathe Flash, we're still playing a bit of catch up to natively duplicate the animation capabilities that Adobe's old technology provided us.  Of course we have canvas, an awesome technology, one which I highlighted 9 mind-blowing demos.  Another technology available...

  • By
    LightFace:  Facebook Lightbox for MooTools

    One of the web components I've always loved has been Facebook's modal dialog.  This "lightbox" isn't like others:  no dark overlay, no obnoxious animating to size, and it doesn't try to do "too much."  With Facebook's dialog in mind, I've created LightFace:  a Facebook lightbox...

Incredible Demos

  • By
    MooTools FontChecker Plugin

    There's a very interesting piece of code on Google Code called FontAvailable which does a jQuery-based JavaScript check on a string to check whether or not your system has a specific font based upon its output width. I've ported this functionality to MooTools. The MooTools...

  • By
    MooTools & Printing – Creating a Links Table of Contents

    One detail we sometimes forget when considering print for websites is that the user cannot see the URLs of links when the page prints. While showing link URLs isn't always important, some websites could greatly benefit from doing so. This tutorial will show you...

Discussion

  1. this article very nice,,

    please share take widget recent post as this site . . .

    :D

    thanks

  2. It’s time to start using those features as the growing number of tablet users becomes a noticeable change to the visitors on my sites.

  3. Matthew Blancarte

    Gotta love window.orientation.

    I always stick to the js solutions on this part of a build… media queries have failed me too many times.

    Using a combination of window.devicePixelRatio and screen.width always works for me. :)

  4. Matthew Blancarte

    Something like this:

    var deviceFix = function()
    {
        var pixelRatio = window.devicePixelRatio;
        var screenWidth  = screen.width;
        
        //Retina
        if( pixelRat >= 2 ){}
    
        //iPhone 3gs, 3g, Edge
        if( pixelRat < 2 && screenWidth === 320 ){}
    
        // etc.
    }
    
  5. windows phone 7 have a bug with orientation I wrote about a few months ago:
    http://gmadar.com/windows-phone-7-browser-orientation-detection/

  6. Brad

    I noticed that on my Android 2.3 device the orientationchange event fires before the resize event, which means that any screen measurements taken within an orientationevent are inaccurate unless, as I was forced to do, you delay the measurements by 500ms. Simply using a resize event might work in some cases.

    • omg Brad you saved me!
      I have a section which is like a landing page on my website, the height of this element depends on the users screen height. its great but when the device changes orientation it doesnt fit right anymore, so i needed to re-adjust the element height upon orientation change.
      I had JQuery event listeners for “orientationchange” and adjusted the height but it didnt work until it was refreshed. added an alert to display var holding screen size, and if i kept changing orientation it kept displaying the previous window height of the last orientation.
      I saw your comment on the 500ms delay and it all made sense, the orientation event happens before the browser resizes anything too.

      So by using the “resize” JQuery listerner and applied height change in there it all worked beautifully. thankyou soo much :)

  7. Joni Sakasho

    Immensely useful! I went with the matchMedia, because it seems that there has been issues with the orientationchange event.
    Thanks for this and so many other useful posts! =)

  8. Stace Merkel

    This might be an easy question but I’m new to dojo mobile and CSS/JavaScript. Is there a way using the deviceFix function (or maybe CSS media queries) above to resize icon1 and icon2 for a dojo mobile tabbarbutton so that iOS retina icons can be used? I have been trying to find an example of retina support in dojo mobile and so far have come up empty handed. Please help! Thanks!

    • Tapani

      If dojo used css background image this could be done using “background-size: contain”. But because it uses tag there is nothing you can do.

  9. “If you’d like to get clever, you can code a periodical “watcher” with JavaScript to check the background colour of a block and fire your own orientation change.”

    HAHAH! Oh man, I thought I was the only one who’s been doing that. :’) Good to know I’m not alone.

  10. As we say at home: “EVALA!” (==BRAVO)!

    this very line @media screen and (orientation:portrait) { saved me!

    Thank you, keep rockin’!

    Regards,
    Ivan

  11. I changed my listener from orientationchange to resize and it looks like it has fixed a problem relating to Android using Chrome browser. I have a website that uses Google Maps API release 3 and it seemed that when you changed orientation that sometimes the map broke. Have tried it quite a few times now using the resize event and it looks good so far. I got my fingers crossed.

    I appreciate your post as well as the comments. One commented that he observed the orientationchange firing first followed by resize. This may be what I was seeing .

    Thanks again,
    Al

  12. In Windows 8 this doesn’t work..((

  13. orientationchange event is often supported but badly implemented. It’s pretty unreliable on anything but the iPhone. Also note that orientation in media queries reflects just the width/height ratio. Ironically the browser can report a landscape media query even if the device is actually in portrait (eg: on old iphone with url bar+debug_console+bottom_bar open).

  14. dan

    Here’s code to detect native onorientationchange support:

    if("onorientationchange" in window) {
           //then supports!
    }
  15. Awesome David..

  16. Very useful, thanks. Here’s how it helped me: http://dontwakemeup.com/vw-units-and-iphone-orientation-change/

  17. very nice!, that is all i want to say

  18. I had a problem where changing orientation back and forth made my menu button go off-screen.
    After a while I discovered this interesting fix:

    @media (orientation:portrait) {	
    	body{}	
    }
    
    @media (orientation:landscape) {	
    	body{}	
    }
    

    Tested with Samsung Galaxy S3, Lumia 520, iPhone 4S and iPhone 5.

  19. The resize event at page load sometimes fires 2 or 3 times in Firefox for Android. Sometimes it doesn’t fire at all. When the device is rotated it fires twice. If you have multiple places where you set up resize event listeners, the 3rd one might wait 3 or 4 seconds after you’ve rotated the device before it is triggered.

    In Chrome for Android and Safari iOS the resize event never fires at page load.

    In the current Chrome for Android (as of 2014-02-01) when you scroll a long page up and down the address bar appears and disappears. Each time the address bar changes, Chrome fires a window resize event. Both Firefox and Safari have address bars that behave similarly visually but neither fires a resize even when their bars appear/disappear.

    On desktop all the browsers (I think) fires multiple resize events every few milliseconds as you are resizing the window. This causes your even handler functions to be triggered many many times.

    To prevent this you can delay when you code is run using techniques like http://www.marcuspope.com/better-resize-event-handler

    But when using that both Safari iOS and Chrome Android will not trigger that code when the device is rotated the first time. Every time after that it will work.

    In firefox for android it will only sometimes fire at page load and will sometimes have a 2 to 4 second delay before firing after rotation change. But I think it only behaves this way if you also have non delayed window resize events set up to happen before the delayed resize code.

    This is painful.

    The only other one I’ve tested so far is MatchMedia and it seems to have no issues in iOS safari and Android Chrome & Firefox.

    • Subham

      Thanks a lot for these details. This is old but they still haven’t fixed these issues..

  20. Hello world!
    Intriguing point about innerWidth and outerWidth. Can someone elaborate please?

  21. Praveen

    hi david,
    Thanks for your orientation checking solution.

  22. pike

    It seems – this sounds obvious – the orientation event isn’t triggered if, in your app, the orientation is locked.

    MDN says chrome supports something called ‘deviceorientation’ :
    https://developer.mozilla.org/en-US/docs/Web/API/Detecting_device_orientation

    And lo and behold, apple follows
    https://developer.apple.com/library/iad/documentation/SafariDOMAdditions/Reference/DeviceOrientationEventClassRef/DeviceOrientationEvent/DeviceOrientationEvent.html

    $2c,
    *-pike

  23. In CSS if you use this

    /* portrait */
    @media screen and (orientation:portrait) {
    	/* portrait-specific styles */
    }
    /* landscape */
    @media screen and (orientation:landscape) {
    	/* landscape-specific styles */
    }
    
    to determine orientation you will have a problem with when keyboard is showing height will be smaller the with I will recommend to use:
    /* portrait */
    @media screen and (max-aspect-ration: 13/9) {
    	/* portrait-specific styles */
    }
    /* landscape */
    @media screen and (min-aspect-ration: 13/9) {
    	/* landscape-specific styles */
    }
    

    The rest is almost all I already use so your article is pretty well written. Keep-up

  24. kumar

    Hi!
    I am following the technique what is suggested above…which is working fine but only when I am changing the orientation of mobile…at page load its not reflecting any thing.

  25. Hi David,

    Great blog!

    Just wanted to mention that if you log (or alert)

    console.log(screen.orientation)

    you will only get [object ScreenOrientation]. If you want the angle, you’d need to do

    console.log(screen.orientation.angle)

    .

    Thanks again!

  26. Chandimal

    Hi,

    This is the best solution even work in ios. Thank you so much

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!