Tactile Mobile apps are where it's at - they've revolutionized the user experience to become so intuitive that even babies claw at their parent's phones to make the pretty lights move with their fingers.
We are no longer talking about clicking, double-clicking and dragging, but about tapping, holding, pinching and swiping.
With this revolution come certain expectations. I now expect an immediate response to my gestures and to have the phone sense when I turn it and adjust accordingly.
This post is about how to meet the user's expectations around resizing when developing HTML5 in the mobile browser.
"But isn't that the browser's job to layout my app properly no matter which way the phone is turned?" I hear you ask.
No. Unless your web app is really just a web page with no special layout restrictions, you are mistaken to think that the browser will do this for you with no effort on your part.
First of all, play with your phone's browser a little to understand what it does with a regular web page. Don't get caught in that 'false security zone' which makes your brain think that it's so intuitive that it always knows what it's doing. After a few minutes you'll probably be surprized at what you thought you knew.
One common scenario is that the browser zooms out to a predetermined width by default, making the page elements look very small and sometimes illegible. This is great when you're browsing the web, but not what you want when displaying a web app UI. So the first thing you should know is that there are special HTML5 mobile directives which tell the mobile browser how to present your web page.
I won't go into that here, there are plenty of references on the internet, like this one:
http://learnthemobileweb.com/2009/07/mobile-meta-tags/
However, I will tell you that what you probably want is this configuration:
<meta name="MobileOptimized" content="width" ><meta name="HandheldFriendly" content="true"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
This will encourage the phone to size your page to the width of the device, disable the ability to pinch-zoom the page content, and prevent the browser from scaling your content when rotating the phone.
But what about more complex layouts?
A common goal for mobiles apps is the iPod interface layout on the iPhone: A header bar along the top with back and forward buttons either side of the title, a toolbar with icons along the bottom and a scrollable area in the middle showing a list of things (Artists/Tracks/Genres, etc).
One of the fundamental differences with browsers compared to application layouts is that fixed height layouts are hard to implement. The idea being that if you constrain the width the content must be shown and should therefore flow down. Doing fixed height layouts on browsers has often been a challenge. On mobile, the challenge has been further complicated by the fact that internal scroll areas have encountered problems. (iPhone has only in iOS 5 started supporting scrollable divs.) Widgets like iScroll have emerged to try to give web apps the ability to mimic native layouts. However, as I have discussed in previous posts, Android has some serious issues in this area.
However, let's suppose that in an ideal world (i.e. on an iPhone) the center panel scrolls smoothly. What hurdles do we have to leap to support device rotation in the browser?
In essence, assuming the top toolbar stays in place, there are two main things to do: size the central scroll view and position the navbar at the bottom.
This turned out to be a lot harder to implement on Android than on the iPhone.
I came up with a strategy to determine the available screen dimensions and divide up the UI into its proportional parts: status bar, toolbar, content area and navbar. I could then determine the dimensions for each based on the device type and orientation.
Cross-platform (in)compatibility
Things were pretty straight-forward on the iPhone. My strategy seemed sound. The browser did what it was supposed to do and soon I was rotating the device and seeing the layout adjust accordingly. The theory was that this would 'just work' on Android. How wrong I was.
The two main things that made this difficult on Android were:
I soon discovered that the Android browser did not report the physical screen dimensions correctly.
Using jQuery Mobile, Android was also challenged in reporting what mode it was in: landscape or portrait. In fact, much of the time it was opposite to what was reported on iPhone! I discovered that the orientation change was fired from the resize event, and so ended up just working it out from the browser's resize event instead.
To resolve the first issue on Android, I used the bottom css property to compensate for the fact that it could not tell me the dimensions of its own screen. Fortunately this worked, or I would have been really stumped. Ironically, the same approach didn't work on iOS, so I needed to handle each platform differently.
A further issue with the Android resize event is that it gets triggered when the keyboard is up, and reports the new dimensions of the area displayed above the keyboard. And on certain devices, the available height is now less than the available width, which makes the code think it's in landscape mode! What's more, the navbar is repositioned just above the keyboard, since that is now, temporarily the bottom of the webpage... Grief like this makes you wonder if it's worth it!
iOS Standalone Mode
On iPhone, you can save a web app to the Home screen. You will want to tell the iPhone that your app supports this mode using this directive in your HTML page's head section:
<meta name="apple-mobile-web-app-capable" content="yes"/>
You can even define a custom home page icon and loading image:
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="images/icon-114.png" /><link rel="apple-touch-icon-precomposed" href="images/icon-57.png" /><link rel="apple-touch-startup-image" media="mobile" href="images/fl_startup.png" />
This is awesome for mobile web developers who don't need the App Store. This mode gives a less cluttered interface to the user, and makes the app feel more like a native app than a webapp. The address bar no longer is accessible, and the web browser's toolbar is gone. :)
In javascript, Apple provides a special flag to determine the mode you're in:
window.navigator.standalone
You can use this to help when laying out code to determine whether the web toolbar is taking up space.
Supporting high resolution displays
Here's an example of how to use a high resolution image on wide or high pixel density devices:
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),only screen and (min-resolution: 240dpi) {.ui-icon-spinner {background-image: url(../images/spinner@2x.gif);}.ui-icon-spinner {-webkit-background-size: 16px 16px;background-size: 16px 16px;}}
CSS Only Solutions
This is a bit beyond the scope of this article, but there's a school of thought that CSS3 media queries can be used to cater for 90% of the situations without 'resorting' to code. The irony is that the media queries themselves are quite 'code-like' in their formulation, and so it's really just a case of picking your poison.
However, the possibility exists to do some great things with layout on different sized devices using CSS3 queries. A classic example is to define a layout which stacks layout blocks vertically for small devices, but horizontally for larger devices like tablets and desktop browsers. One can even hide certain elements when available screen space is at a premium.