(For more resources on this topic, see here.)
Introduction
While there are many operating systems (OS) as well as device makers, inevitably there could be cross-browser issues that cost us a lot of headaches. But on the other hand, we developers love the challenges and set out to tackle them!
Throughout this article, we will first focus on cross-browser/browser-specific setup and optimizations you may want to consider. We will then go on to look at a couple of general/ browser-specific features you may want to add at the start of your mobile development.
Adding a home screen button icon
Target devices: iOS, Android, Symbian
On modern smartphones, screens are mostly touch based. The iPhone revolutionized the way we think of mobile by making everything on your device an “app”; even SMS and phone dialing behave like apps with an icon on the home screen. For an HTML web app, things are a bit different; users have to go to a browser app first, type in the address and then launch your site. This can be too much hassle from a user perspective, so on certain smartphones, users can bookmark a home screen icon to a particular web app, so they can launch that particular web app site directly from the icon on their home screen.
That sounds cool, right? Yes, it does, but there are also issues associated with it. Not all browsers behave the same way when it comes to touch icons. In this recipe, we will examine the behavior of each browser and how to make home screen icons available to as many mobile browsers as possible.
Getting ready
First, you have to download the icon sets from the chapter code folder. If you open up the folder, you should be able to see the following:
apple-touch-icon.png
apple-touch-icon-57×57-precomposed.png
apple-touch-icon-72×72-precomposed.png
apple-touch-icon-114×114-precomposed.png
apple-touch-icon-precomposed.png
These images will be used for different devices.
Create an HTML document and name it ch02r01.html.
How to do it…
In your HTML document, use the following code:
<!doctype html>
<html>
<head>
<title>Mobile Cookbook</title>
<meta charset="utf-8">
<meta name="viewport" content="width= device-width,
initial-scale=1.0">
<link rel="apple-touch-icon-precomposed"
sizes="114x114" href="icons/apple-touch-icon-114x114
-precomposed.png">
<link rel="apple-touch-icon-precomposed"
sizes="72x72" href="icons/apple-touch-icon-72x72
-precomposed.png">
<link rel="apple-touch-icon-precomposed"
href="icons/apple-touch-icon-precomposed.png">
<link rel="shortcut icon" href="
icons/apple-touch-icon.png">
</head>
<body></body>
</html>
How it works…
Now let’s break down the code:
As of iOS 4.2.1, it’s possible to specify multiple icons for different device resolutions by using the sizes attribute.
<link rel="apple-touch-icon-precomposed"
sizes="114x114" href="apple-touch-icon-
114x114-precomposed.png">
For high resolution retina displays on iPhone 4, a 114 x 114 icon is used.
<link rel="apple-touch-icon-precomposed"
sizes="72x72" href="apple-touch-icon-
72x72-precomposed.png">
For iPad, a 72 x 72 icon can be used. For non-retina iPhone, Android 2.1+ devices, a 57 x 57 low resolution icon is used.
<link rel="apple-touch-icon-precomposed"
href="apple-touch-icon-precomposed.png">
For Nokia Symbian 60 devices, a shortcut icon is used in link relation to tell the device about the shortcut icon.
<link rel="shortcut icon"
href="img/l/apple-touch-icon.png">
Here is what the bookmark looks like on Android:
There’s more…
There must be a couple of questions in your mind after seeing the previous example:
- Isn’t it possible to define more than one value in the rel attribute? So can we combine the last two lines into something as follows?
<link rel="shortcut icon apple-touch-icon-precomposed"
href="apple-touch-icon-precomposed.png">It was tested, but somehow mobile browsers couldn’t recognize the value.
You might have seen people use:<link rel="apple-touch-icon-precomposed"
media="screen and (min-resolution: 150dpi)"
href="apple-touch-icon-114x114-precomposed.png">
Together with Paul Irish and Divya Manian, we have been working on Mobile Boilerplate (http://www.h5bp.com/mobile) that provides a rock-solid default for frontend mobile development. In Mobile Boilerplate, we have covered all the current scenarios and possible future scenarios:
https://github.com/h5bp/mobile-boilerplate/blob/master/index.html#L21
Everything you always wanted to know about touch icons
Most ideas presented on this topic are originated from Mathias Bynens. His original article Everything you always wanted to know about touch icons can be found at:
http://mathiasbynens.be/notes/touch-icons.
Official documentation about Apple touch icons
There is a list of official documentation where you can find more information about touch icons for each specific device and browser:
- Apple touch icon:
http://developer.apple.com/library/safari/#documentation/ AppleApplications/Reference/SafariWebContent/ ConfiguringWebApplications/ConfiguringWebApplications.html - Official information from WHATWG:
http://www.whatwg.org/specs/web-apps/current-work/multipage/ links.html#rel-icon
Apple Custom Icon and Image Creation Guidelines
Guidelines and articles about how to create a touch icon can be found at the Apple – Custom Icon and Image Creation Guidelines article:
http://developer.apple.com/library/ios/#documentation/ userexperience/conceptual/mobilehig/IconsImages/IconsImages html#//apple_ref/doc/uid/TP40006556-CH14-SW11.
Preventing text resize
Target devices: iOS, Windows Mobile
On certain mobile devices like the iPhone and Windows Mobile, browser text may resize when you rotate the device from portrait to landscape mode. This could be problematic to web developers because we want to have full control of the design and rendering of the website.
Getting ready
Create a new HTML file, and name it ch02r02.html. Enter the following code:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<style>
figure, figcaption, header {
display:block;
margin:0 auto;
text-align:center;
}
</style>
</head>
<body>
<header>
HTML5 Logo
</header>
<figure>
<img src="HTML5_Badge_128.png" alt="HTML5 Badge" />
<figcaption>
It stands strong and true, resilient and
universal as the markup you write.
It shines as bright and as bold as the
forward-thinking, dedicated web developers
you are.
It's the standard's standard, a pennant for
progress.
And it certainly doesn't use tables for layout.
</figcaption>
</figure>
</body>
</html>
Now render this page in portrait mode in iPhone, as you can see, it will be rendered normally as follows:
Now if you render it in the landscape mode, the font size will suddenly increase. As we can see when the page is changed to landscape mode, the text will get resized. This is not the desired behavior. The following shows how it looks:
How to do it…
You can follow these steps to fix the issue:
- You can add the following lines to the CSS, and then render the page in landscape again:
html {
-webkit-text-size-adjust: none;
} - As You can see, the text now appears normal:
How it works…
To solve this issue, you have to add a CSS property named text-size-adjust in WebKit, and assign the value to none to prevent the auto adjust.
Setting text-size-adjust to none solves the problem for mobile-specific websites, but if we render this on a desktop screen or other non-mobile browser, the desktop browser text zoom feature will be disabled. To prevent this accessibility issue, we can set text-size-adjust to 100% instead of none.
So we can tweak this example to:
html {
-webkit-text-size-adjust: 100%;
}
There’s more…
Apart from iPhone, other devices also have ways to add the text size adjust property.
Windows Mobile
Windows Mobile IE uses a different prefix. They originally added the WebKit prefix. The intent was adding support for the WebKit-specific property to make web developers’ lives a bit easier by not having to add yet another vendor-prefixed CSS property to their pages to control how text was scaled. Even more specifically, they intuited that the most common use case for this property was to explicitly set it to none in order to tell the browser not to scale a particular section of the text.
After hearing the community’s feedback on this issue (and a couple of face-plants when they realized the broader implications of implementing other browser vendors’ CSS properties) they’ve decided that it’s best to only implement the -ms- prefixed version and not the -webkit- one.
So to make the preceding example more complete, you can add:
html {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
Making it future proof
To make things more future proof, you can add one more line without any prefix, as follows:
html {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
text-size-adjust: 100%;
}
px em, which is better?
The common debate about using px versus em is less of a problem on mobile. Originally Yahoo! User Interface used ems for the reason that IE6 doesn’t support page zoom with pixels. On mobile, there isn’t such an issue, and even if we want the page to render well on desktop browsers, the likelihood of someone using IE6 is getting lower and lower, so in most cases, you can save the trouble of using ems and all the calculation, and choose instead to use pixels.
Optimizing viewport width
Target device: cross-browser Different mobile devices have different default mobile viewport widths. Refer to Appendix X for a complete list of default viewport widths for all mobile devices. If you leave it unset, in most cases, it will cause an unexpected result. For example, in an iPhone if the viewport width is left unset, it will be rendered as 980 px.
Getting ready
Let’s create an HTML document and name it ch02r03.html.
How to do it…
Here is what we can do to optimize the viewport width:
- Add the following code to ch02r03.html and render it in your mobile browser:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<header>
HTML5 Logo
</header>
<div id="main">
<h1>Lorem ipsum</h1>
Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit
in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.
</div>
</body>
</html>Here is how it’s rendered by default:
- If we render this example, we can see that everything becomes extremely small. Now, let’s set the viewport width to the device width:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<header>
HTML5 Logo
</header>
<div id="main">
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit
in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.</p>
</div>
</body>
</html>Now the content width uses the screen width and the text becomes readable:
How it works…
When we set viewport width to device-width, it will tell the browser not to scale the page to fix the device area. So for iPhone, the device-width is 320 px in portrait mode and 480 px in landscape mode.
There’s more…
For some really old relic mobile browsers, the meta attribute isn’t recognized. To deal with these browsers, you need to use:
<meta name="HandheldFriendly" content="true">
This is used by older versions of Palm OS, AvantGo, and Blackberry.
<meta name="MobileOptimized" content="320">
For Microsoft PocketPC, a MobileOptimized attribute was introduced.
So the most complete code should look like:
<meta name="HandheldFriendly" content="true">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width">
IE for Windows Phone viewport blog post
On IE for Windows Phone Team Weblog, there is an article about IE Mobile Viewport on Windows Phone 7. In it, the author has explained important information like how Windows Phone 7 implements “device-width”, together with much other very useful information in general. You can read the article here:
http://blogs.msdn.com/b/iemobile/ archive/2010/11/22/the-ie-mobile-viewport-on-windows-phone-7.aspx
Safari documentation
Safari has a reference in the developer’s library at:
http://developer.apple. com/library/safari/#documentation/appleapplications/reference/ SafariHTMLRef/Articles/MetaTags.html
Blackberry documentation
There is a Blackberry Browser Content Design Guidelines document. It explains Blackberry’s use of viewport width:
http://docs.blackberry.com/en/developers/ deliverables/4305/BlackBerry_Browser-4.6.0-US.pdf.
Fixing Mobile Safari screen re-flow scale
Target device: iOS
Mobile Safari has an annoying screen re-flow bug: When you rotate the mobile browser from portrait mode to landscape mode, the text will suddenly jump to a bigger size. During the time I was working on building Mobile Boilerplate, Jeremy Keith and I had a long discussion on this issue.
The traditional way of fixing this is to add the following scaling attributes to the meta viewport:
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
This solution was first incorporated into Mobile Boilerplate. Jeremy pointed out that this solves the scale jump problem, but at the same time, it causes another issue with accessibility: When you set the values as shown above, you can no longer zoom the page to enlarge it. For people with eyesight problems, the ability to zoom is essential. But if we let the zoom happen, the text jump will annoy the majority of the users. So, for a long time it was an accessibility versus usability debate.
I discovered a method that could tackle the issue and we will discuss this next.
Getting ready
First, let’s create an HTML document and name it ch02r04.html, enter the following code in it:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
</head>
<body>
<div>
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit
in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.</p>
</div>
</body>
</html>
This page renders perfectly fine in portrait mode:
But when displayed in landscape mode, things change:
How to do it…
All we need to do to solve this problem is to dynamically reset the scale factors to default when the user zooms in on the page. Now put the following code in your HTML document:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
</head>
<body>
<div>
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit
in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.</p>
</div>
<script>
var metas = document.getElementsByTagName
('meta');
var i;
if (navigator.userAgent.match(/iPhone/i)) {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport") {
metas[i].content = "width=device-width,
minimum-scale=1.0, maximum-scale=1.0";
}
}
document.addEventListener("gesturestart",
gestureStart, false);
}
function gestureStart() {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport") {
metas[i].content = "width=device-width,
minimum-scale=0.25, maximum-scale=1.6";
}
}
}
</script>
</body>
</html>
Now if we rotate the screen from portrait to landscape, the issue should no longer exist, and if we zoom in on the page, it will react as expected:
How it works…
Let’s have a walk through of the code to see how it works.
- We need to know the default minimum-scale and maximum-scale values. In the iPhone’s official documentation, it states that the minimum-scale value is 0.25, and the maximum-scale value is 1.6. So to replace the default value, we need to set:
function gestureStart() {
var metas = document.getElementsByTagName
('meta');
var i;
for (i=0; i if (metas[i].name == "viewport") {
metas[i].content = "width=device-width,
minimum-scale=0.25, maximum-scale=1.6";
}
} - Next, we need to know when to set this. This is very easy: The iPhone has a gesture event listener we can use to target the document body. Here is how to do so:
document.addEventListener("gesturestart",
gestureStart, false); - Finally, we need to make sure this only happens on iPhone. Again this can be easily done using:
if (navigator.userAgent.match(/iPhone/i)) {
document.addEventListener("gesturestart",
gestureStart, false);
}
There’s more…
If you are interested to know the whole story and discussion between Jeremy and I, you can read it at http://www.blog.highub.com/mobile-2/a-fix-for-iphone-viewportscale- bug/.
Even though this provides a fix for the issue, there are a couple of problems that some people experience:
- As soon as the user makes a gesture on the document, zooming is enabled again. So if you change the device orientation after that, the zoom bug will still occur.
- It’s reported on iOS4 that users can only effectively start zooming after starting a second gesture.
A slightly improved version
Mathias Bynens has a revised version with smarter coding. You can see the code at:
https://gist.github.com/901295
An even better version
John-David Dalton had an even better updated version with smarter and leaner code at:
https://gist.github.com/903131
A word for jQuery Mobile
Scott Jehl from jQuery Mobile mentioned it might be implemented in jQuery Mobile in the future. Currently, you could see his gist at:
https://gist.github.com/1183357