Stefan Baumgartner

Web ops, performance and front-end

Robust (but hacky) way of portrait / landĀ­scape detection

16 April 2012 by @ddprrt | Posted in: HTML5, Javascript, Mobile

On mobile devices it's pretty easy (and in some cases also pretty cool) to change the look of your website respectively to the orientation of your device with media queries. However, sometimes the orientation does not only affect your layout, but also the routines of your Javascript. This article shows some possibilites how to detect portrait/landscape orientation on your mobile device. Some are less robust considering multiple device vendors, and some are in exchange a lot more hacky. You're gonna love it.

When searching for portrait/landscape orientation detection we mostly get the following, well known results on Stackoverflow and consorts:

window.onorientationchange = function() {
  switch(window.orientation) {
    case 0:
      //do portrait stuff
      break;
    case 90:
      //do landscape stuff
      break;
    case -90:
      //do landscape stuff
      break;
    case 180:
      //do portrait stuff upside-down
      break;
  }
}

Pretty easy to understand: When the device changes it's orientation, check the degrees of your device, and in case of 0 or 180 degrees it's portrait mode, landscape mode otherwise. This is true for almost all mobile phones out there and was heavily popularized by Apple and it's Mobile Safari Web Development Documentation.

Samsung Galaxy Tab 10.1 and consorts

The new Samsung Galaxy Tab (and some other devices like Toshiba Thrive) however, do things a little different: Here window.orientation results in 0 degrees respectively 180 degrees in landscape mode.

And acutally, that's okay. That's how the Galaxy Tab should be held by the users. That's it's zero degree orientation by definition. It's just a pain in the ass for us developers.

matchMedia for media queries in Javascript

Media queries are cool for device detection because they're really checking for portrait and landscape orientation, not for the devices degree orientation. And there is actually a way to use media queries in Javascript. Credits to the code snipplet go to David Walsh.
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
  }
});

However, window.matchMedia is not support prior to iOS5 and Android 2.3.

Hacky Media Query solution

But there's another way to bring media queries to your Javascript for this use case. By its roots, the CSS file:

body:after {
  content: "";
  position: absolute;
  color: transparent;
}

@media all and (orientation: portrait) {
  body:after {
    content: "p";
  }
}

@media all and (orientation: landscape) {
  body:after {
    content: "l";
  }
}

We create a body:after pseudo element (because it's always here and doesn't require an extra DOM element) which is placed absolutely (so it doesn't take any space) and has a transparent color (so we don't see its contents). According to our orientation, we change the element's content to respectively.

And this is our Javascript:

//get style of the body:after element
var bodyAfterStyle = window.getComputedStyle(
  document.body, ":after");

window.onorientationchange = function() {
  if(bodyAfterStyle.content == 'p') {
    //do portrait stuff
  } else if(bodyAfterStyle.content == 'l') {
    //do landscape stuff
  }
}

Pretty self explanatory. I know that there're other ways, like calculating with the device window width and height, but there might be some issues because the windows width is defined by its content. So I think it's better to stick with one of the solutions above.

Bottom line: Know your devices and if possible, use window.matchMedia for your orientation detection.

Comments? Shoot me a tweet!