Fixing the iOS Orientation Bug — In Three Steps

Ever notice terrible things happening to your design when you change orientation on an iOS device? Well, you are not alone, friend. That’s a bug, not a feature, and it drives the designer in me crazy. What’s worse is that Apple has known for years and has done nothing about it, so it’s up to us in the web community to find a way to deal with it. More than one factor is at play in this issue, so I’m going try to explain what’s happening and then discuss how to get back to a point of expected behavior.
The Bug
Here’s the behavior of the bug: Let’s say you have a responsive site with a single column layout for mobile devices like the iPhone. When you view this page vertically on the iPhone it looks just fine. But when you flip the phone horizontally, all hell breaks loose. The page gets zoomed in on and cropped by the browser window, and the font size increases too! So the contents of the page are bigger, and only a portion of the page is visible. Not at all what you would expect to see as a user. To get the phone to display the page properly again the user has to double tap the screen, resetting the zoom. Not good. Not only is this behavior undesirable to the designer, who wants their work to be displayed properly — but to the user as well, who shouldn’t have to be put upon with ambiguous and unnecessary interaction to get things look as they should.
How to Squash the Bug
With impunity — just kidding — kind of. Many people have tried to fix the iOS orientation bug in just as many ways. Sadly, no single solution to date has actually solved both the zoom and the width issues on its own. DO NOT DESPAIR! There is hope. You can rid yourself of this bug for good by using the three techniques I’m about to describe to you below.
Where to Begin
Mobile webkit browsers consult a viewport meta tag to determine how display a page. We need to stop our’s from scaling so let’s take a look at the options. We can pass values for width, device-width, height, device-height, initial-scale, minimum-scale, maximum-scale, and user-scalable.
A lot of people have tried the following tag, myself included:
<meta name="viewport" content="initial-scale=1.0,minimum-scale=1.0, maximum-scale=1.0" />
This tag instructs our viewport to be viewed at full-scale at all times. Problem solved, right? Not really. The orientation bug is nullified by this tag, yes — but at the cost of preventing users from zooming! It’s essentially the same as user-scalable=no. People like to zoom and they expect to zoom. It’s established functionality on these devices specifically, so I think that disabling the zoom function is unacceptable. So how can we handle the meta tag in light of that?
The following is my preferred approach to this problem:
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0" />
- By using width=device-width we are telling the browser to make the width of the window match the width of the device it’s being viewed on. The reason to use this instead of a hard numerical value like 320 is to accommodate for more devices (think iPad.)
- Next, with initial-scale=1.0 we’re setting the zoom level on page load to normal; it’s like saying 100%.
- Lastly, minimum-scale=1.0 is telling the browser that we don’t ever want the page to be zoomed out past 100%.
The result is a useful, flexible meta tag that will match the width of device it’s being viewed on, initially display the page at the intended scale, and allow the user to zoom in, but not out. If the page is zoomed out past full-scale it’ll just snap right back. Now I know what you are thinking, “this does not fix the orientation bug” and you are correct. But it is the place to start.
Filling in the Gaps
In the the world of the web it often falls to JavaScript to make up for any perceived shortcomings of the browser, and the iOS orientation bug is no exception. There are many available options but the one I was first aware of and will reference in this article is the work of the super-sharp and talented Scott Jehl from the Filament Group. Basically, it works by using the accelerometer of an iOS device to detect an orientation change, disabling the zoom while the change is taking place, and enabling it once again when it’s finished. Pretty cool — here’s how to implement it.
Start by grabbing the minified source from Scott’s Github page. Once that’s done, paste it into a blank document and name it whatever you like, just be sure to give it a .js extension. The script can also be placed in-line, but linking is the smarter approach because it allows you to manage just one master file that all pages can reference. Next place the new JavaScript file somewhere it can be linked to (I like to put all my scripts in a separate “scripts” folder, but that’s me.) This JavaScript file can be linked to by inserting the following line of code into the head of any HTML document, like so:
<head>
...
<script type="text/javascript" src="http://www.pgrady.com/scripts/iosbugfix.js"></script>
...
</head>
Now our page will know how to resize itself to fit inside the browser window without cropping, in portrait and landscape mode. However, there’s just one more little detail that needs our attention, that irritating font zoom.
The Final Piece
The bad news is, our text is still getting larger in landscape mode. The good news is, this is a relatively easy fix. It’s the key to making everything work as it should, and it also happens to be the piece that has eluded me the longest.
To fix the orientation bug once and for all, just add the following line of code to your CSS:
html, body {-webkit-text-size-adjust: 100%;}
This simple bit of webkit-only CSS is what we’ve been looking for. It accepts the options of auto, none, or a value. Since we know that auto allows our text to get bigger, and none is a nonstarter because it would override the zoom feature of our browsers, that leaves value as our only viable option. And as it turns out, entering 100% for the value adjusts fonts back to normal-size after an orientation change. Now just let that sink in for a bit. It seems very un-intuitive that we’d have to explicitly tell the browser to resize the text back to normal, but there it is.
In the end, I’ve found that combining all three of the techniques above (CSS, JavaScript, and the meta tag) makes for a page that initializes at full-scale, can zoom in but not out past full-scale, can alter its width to fit inside the viewport without cropping in portrait or landscape mode, and reset the text-size after an orientation change. Finally, after all that work, the page reacts as the user expects it to, and is presented as the designer intended — all without sacrificing usability or features. Bug fixed.
Thanks for reading — I was trying be both clear and thorough, but feel free to hit me up on Twitter with questions or comments — or even if you just want to say “Good job!”