Lesson 10: Optimizing for Mobile Devices

Lesson 10: Optimizing for Mobile Devices

Introduction

Our WatzThis app is starting to look impressive (if not marketable). The board of directors would like to know what you've done in the last few weeks. So let's take a minute and look back at what you've accomplished!

  • You built an HTML5 Web app that lights up (and darkens) a mobile Web browser window at the push of a button.
  • You added an entertaining "auto-flip" mode to the app, which provides a bit of atmosphere for disco dancing.
  • You started on some documentation for the app and used jQuery mobile to provide a native-like experience on mobile devices.
  • You used HTML5 geolocation to get the latitude and longitude of the user, and then you used the Google Maps API to show that location on a map.
  • You added a fun SVG animation to the app.

Things are looking great, but we're rapidly approaching the launch deadline for the product! We need to do a few more things to get it ready.

First, we'll add some code to WatzThis so that users can zoom in on the different parts of the app if they choose.

Next, we'll take advantage of some fancy features of iOS (and sometimes Android) to make the app behave more like an installed native app.

Finally, we'll enable a bit more interactivity in the app by creating a cool touch event.

When you're ready, move on to the next chapter and let's get started!

Understanding the Viewport

If you have a smartphone or tablet nearby, here's something I want you to try right now. Open the Web browser on the device, and then resize it so that it takes up only half the width of your device's screen. Go ahead and do it. I'll wait here.

Did you do it? I'm willing to bet not—because it's impossible to do on every smartphone and tablet that I know of.

This is a big difference between mobile browsers and desktop browsers—mobile browsers are a fixed size. This difference, plus the fact that mobile device screens are typically smaller than desktop screens, changes the way people view webpages on mobile devices.

Open full size version Mobile browsers have fixed widths

The area on your browser where content shows up is the viewport. Think of it as a window (or port) through which you view a webpage.

Initially, most mobile browsers display webpages so that they fit in the viewport. On a site designed for desktop browsers, this is often far too small to be read. So users zoom in on the page. The size of the viewport stays the same, but the size of the webpage increases.

Open full size version Mobile browser displaying an un-zoomed web page

Mobile browser displaying a zoomed webpage

To figure out what's going on here, you need to understand the difference between device pixels and viewport pixels, which is what I'll tell you about next!

Device Pixels and Viewport Pixels

In Lesson 9, you learned about the basic building block of the pictures (and text) that show up on your screen: the pixel. In this lesson, you'll learn why a pixel isn't always a pixel.

There are actually two types of pixels. Device pixels are the actual physical dots that the device screen can display. On the iPhone 6, this is 1334 x 750 (which one is the width depends on how you're holding the device).

A display pixel, also known as a device-independent pixel, a point, or a dot, is what the browser uses to display webpages. It's also what you're using when you specify dimensions in CSS.

Depending on the zoom level, a device-independent pixel may be larger or smaller than a device pixel. You can use a ratio to show the zoom level. For example, if you zoom in to double the size of the content, the ratio of device-independent pixels to device pixels is 2:1 (read this as "two to one"). In other words, display pixels are twice the size of device pixels.

You can control the size of display pixels by controlling the width of the viewport. You do this using the viewport meta tag.

On iOS, the mobile Safari browser uses a default value of 980 points wide in either landscape or portrait mode. In landscape mode, the browser zooms in on the page a bit to take advantage of the larger width. The viewport size remains the same.

This 980-point-wide viewport works great if you've designed your site to be 980 pixels wide and your fonts are readable on a small screen. More often, what you see by default on iOS is something like this:

Open full size version A desktop site on a mobile browser

If, on the other hand, you design your Web app to be 320 pixels wide in portrait mode, but you use the default viewport width (980), your app will take up about a third of the viewport.

Open full size version 320-pixel-wide Web page with the default viewport

To display your webpage as large as possible in mobile browsers, and to take into account that different devices have different scene sizes, you need to set the viewport equal to the width of the device screen. You can do this with a simple HTML meta tag: the viewport meta tag.

<meta name="viewport" content="width=device-width, initial-scale=1.0">

This tag sets the width of your viewport to the width of the device, rather than 980 points, and sets the initial scaling of your viewport to 1—meaning that it won't be zoomed in. The following figure shows the result of just adding this meta tag to the header of the previous HTML page:

Open full size version Setting the viewport width to device-width

The viewport meta tag has a couple of other, less frequently used properties that you might want to know about.

  • height: This specifies the height of the viewport. You don't usually need to worry about this one, as it probably won't do anything.
  • minimum-scale: This one's the minimum amount the user can zoom out to. On mobile Safari, it has a default value of .25, meaning that users can view content at one-quarter of the actual size.
  • maximum-scale: It's the maximum amount the user can zoom in. The default on mobile Safari is 1.6.
  • user-scalable: This property has a value of yes or no. If it's set to no, the user won't be able to zoom.

As promised in Chapter 1, I'm going to show you how to allow users to zoom in on different parts of the WatzThis.com app. Follow these steps:

  1. Open the latest version of the WatzThis.com index.html.

  2. In the header of the page, find the viewport meta tag. It looks like this:

    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />

    Change the value of the user-scalable property from "no" to "yes," and add the width property. Your viewport meta tag should now look like this:

    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  3. Save the page, and then try it out! If you have a mobile device to test it on, upload it to your Web server and try it, or go to www.watzthis.com/L10/watzthis/index_scale.htmlOpens in new windowTry zooming in on the screen by using the standard iOS-style "pinch" touch gesture.

Here's what WatzThis.com looks like zoomed in on my Android phone:

User-scalable property allows the user to zoom in

In Chapter 3, we'll discuss about ways you can make your app look even more impressive.

Native-like Enhancements

Some mobile devices—especially the iPhone and iPod touch—support additional meta tags beyond viewport for making Web apps look good.

One of the most obvious differences between an app that you download from an app store and a Web app is that Web apps usually appear within a browser window.

Apple's iOS provides a way to make Web apps launch in full-screen mode . . . that is, without the browser address bar and controls that take up part of your screen when you're browsing webpages with mobile Safari.

If you have an iOS device (iPhone, iPad, or iPod touch), you see what full-screen mode looks like by visiting the Financial Times at app.ft.com. You'll see a pop-up on the screen that tells you to add a link to the home screen.

App.FT.com encouraging you to add the app to your home screen

If you follow the instructions, iOS will add a link to app.ft.com to your home screen. This link looks very much like a link to a native app.

A home screen link to the Financial Times Web app

Now here's where the magic happens. When you click this home screen link, the Financial Times Web app opens in full-screen mode.

Financial Times Web app in full-screen mode

Notice that the address bar (at the top) and the navigation bar (at the bottom)—which are both normally visible while you browse Web apps—are gone! As a result, the app has significantly more breathing room, and it "feels" more like a native app.

Making a webpage load in full-screen mode (which Apple calls "Web App Mode") when launched from the home screen is surprisingly simple. Are you ready? Here's all it takes:

<meta name="apple-mobile-web-app-capable" content="yes">

I added this meta tag to WatzThis.com, and here's the result when I load it from the home screen with the iPhone simulator:

WatzThis app rendered on a smartphone in full-screen mode

Full-screen mode looks great, but you should be aware of a couple of things (besides that it only works on the iPhone and iPod Touch).

First, there's no way to force the Web app to open in full-screen mode. The only way it will happen is if the user adds the app to his or her home screen and then launches it from the home screen. In practical terms, this means you can't really count on having that extra space. You still need to design your app as if the browser controls will be there.

This brings us to the next point: In full-screen mode, none of the standard browser features are there (such as the Back and Forward buttons and the address bar). This means your app has to have its own navigation buttons so that the user doesn't get stuck somewhere with no way to escape.

The Home Screen Icon

When you add an app to your home screen, iOS creates an icon from the page that you were browsing when you clicked the Add to Homescreen link. Here's what my iOS button looked like for WatzThis:

My WatzThis icon

Android supports adding Web bookmarks to the home screen, but it doesn't create an icon for you. Instead, it will display the Android bookmark icon.

The Android bookmark icon

Both iOS and Android let you customize what the home screen icon looks like. To control what shows up for the home screen icon, you can specify "apple-touch-icon" in a link tag. Note that this link tag uses the name "apple" for both Android and Apple products. This is just a result of Apple having invented it.

Here's how you specify the home icon for the iPhone 4 and newer (with iOS7):

<link rel="apple-touch-icon" sizes="120x120" href="img/h/apple-touch-icon.png">

Here's how you specify the home icon for iPad2 and iPad mini:

<link rel="apple-touch-icon" sizes="76x76" href="img/m/apple-touch-icon.png">

And here's how you specify it for newer iPads:

<link rel="apple-touch-icon" sizes="152x152" href="img/l/apple-touch-icon.png">

You can include all of these in your app at the same time, and the device will choose the most appropriate graphic.

These same link tags will also work on Android.

Making a Splash (Screen)!

A splash screen is an image that displays while your app is loading. You can create a splash screen by using an apple-touch-startup-image link:

<link rel="apple-touch-startup-image" href="img/l/splash.png">

The image you specify here must be 320 x 460 pixels (in portrait orientation) for the iPhone and iPod touch, and 1004 x 768 pixels for the iPad.

Hiding the Status Bar

Even when you're using a Web app in full-screen mode, the iOS status bar still displays at the top of the screen. The status bar is the gray bar with the time and battery status in it. While there's no way to hide this bar, you can change its color and cancel out its effect on your page layout by using the following meta tag:

<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

By setting the value of this meta tag to black-translucent, you give your app access to the whole screen and make the status bar overlap it.

Changing the status bar

You can also use values of default, black, and gray with this meta property. Setting it to just black or gray (the default) will change the color of the status bar but won't cause it to overlap your content.

In Chapter 4, we'll discuss about touch screens. See you there!

Getting in Touch with Touch Events

Many, or perhaps even most, smartphones and tablets have touch screens. In order for webpages to work in an intuitive way on these devices, they need to be able to respond to touch events. By default, mobile browsers convert your taps on the screen into click events, thus allowing you to navigate normal webpages. But much more is possible by writing some JavaScript code.

The four basic types of touch events are:

  • touchstart: This one gets triggered when a finger touches the screen (or other touch-sensitive device).
  • touchmove: This one sends when a finger moves on the screen.
  • touchend: It sends when you lift your finger from the screen.
  • touchcancel: This one sends when the system cancels tracking the touch. This may happen, for example, if the user is in the middle of a touch event and an email comes in.

By detecting combinations of these events, their duration, and their direction (where applicable), the browser can detect events such as swipes (one or more fingers sliding across the screen).

Making Gestures

Many mobile devices also recognize multi-touch events, also known as gestures. Examples of gestures include the "pinch" gesture for zooming or shrinking the contents of the screen on iOS. We'll stick with single-touch events to keep things simple.

In this chapter, we're going to add a touch event to WatzThis.com that will cause the ghost animation to reverse direction when you swipe the screen in the opposite direction from which it's currently moving. To enable this, we're going to use a JavaScript library called SwipeSense.

Let's get started! Follow these steps:

  1. Go to PadiliciousOpens in new window and locate the link to the JavaScript code. Or go directly to the JavaScript codeOpens in new window.
  2. Copy the entire contents of the JavaScript listing to your computer's clipboard.
  3. Open the latest version of the WatzThis.com index.html in Komodo Edit, and paste the JavaScript that you copied to your clipboard into the page, somewhere between <head> and </head>.
  4. Near the end of the code that you just pasted, find the following function:
    function processingRoutine() {
        var swipedElement = document.getElementById(triggerElementID);
        if ( swipeDirection == 'left' ) {
        // REPLACE WITH YOUR ROUTINES
        swipedElement.style.backgroundColor = 'orange';
        } else if ( swipeDirection == 'right' ) {
        // REPLACE WITH YOUR ROUTINES
        swipedElement.style.backgroundColor = 'green';
        } else if ( swipeDirection == 'up' ) {
        // REPLACE WITH YOUR ROUTINES
        swipedElement.style.backgroundColor = 'maroon';
        } else if ( swipeDirection == 'down' ) {
        // REPLACE WITH YOUR ROUTINES
        swipedElement.style.backgroundColor = 'purple';
    }
    }
    

    This function responds to touch events. Replace this function with the following:

       var swipedElement = document.getElementById(triggerElementID);
        function processingRoutine() {
        if ( swipeDirection == 'left' ) {                        
                               window.frames.ghost.location.href = 'animated_ghost_reverse.svg';
        } else if ( swipeDirection == 'right' ) {
        window.frames.ghost.location.href = 'animated_ghost.svg';
        } else if ( swipeDirection == 'up' ) {
                               alert('up');
        } else if ( swipeDirection == 'down' ) {
                               alert('down');
        }
    }
  5. Locate the <object> element that contains the animated ghost SVG file. It looks like this:
    <object width="100%" height="100px" data="animated_ghost.svg" type="image/svg+xml"></object>

    Replace that line with this one:

    <iframe name="ghost" width="100%" height="100px" src="animated_ghost.svg"></iframe>
  6. One line below that, locate this line:
    <div id="directions">

    and change it to:

    <div id="directions" ontouchstart="touchStart(event,'ghost');" ontouchend="touchEnd(event);" ontouchmove="touchMove(event);" ontouchcancel="touchCancel(event);">
  7. Add a new instruction for this new swiping functionality by adding this line after <ol>:
    Swipe here to reverse the ghost's direction.
  8. Open animated_ghost.svg in Komodo Edit. We're going to make a copy of this file with the ghost's direction of travel reversed.
  9. To make a copy of the file, Choose Save As from the File menu and save it as animated_ghost_reverse.svg in the same folder as the animated_ghost.svg file.
  10. Switch the starting and ending points for the ghost by changing this line:
    <svg x="-100">

    to

    <svg x="350">

    and then change this line:

    <animate attributeName="x" to="350" dur="3s" repeatCount="10" />

    to

    <animate attributeName="x" to="-100" dur="3s" repeatCount="10" /> 
  11. Save animated_ghost_reverse.svg.
  12. If you've done everything right, you should be able to open WatzThis in your browser, and you'll see . . . pretty much the same thing as before. To try out the touch event, you'll need to view it on a touch screen.

If you have a smartphone or tablet with a touch screen, you can try it out by going to www.watzthis.com/L10/watzthis/Opens in new window.

If you don't have a smartphone with a touch screen, never fear! The assignment in this lesson will show you how to install Phantom Limb—a touch simulator for desktop browsers.

Summary

Watzthis.com is nearly ready to release to the world. In this lesson, you learned some important concepts and made improvements so that you have more than just a typical webpage.

You learned about the viewport and the difference between device pixels and display pixels. You then used your new knowledge of the viewport meta tag to set the viewport size of Watzthis.com to the device size and to allow users to scale the app.

After that, you discovered how to invoke Web app mode on iOS, how to create a splash screen, and how to specify home screen icons.

The last part of this lesson was all about touch events. You used a JavaScript library to touch-enable Watzthis.com.

Remember to check out the FAQs and Supplementary Material, do the assignment, and test your knowledge on the quiz. If you have questions or concerns, please visit the Discussion Area and leave me a message. Remember, I want to help you all I can!

In the next lesson, we'll discuss about one of the most important aspects of a mobile app—performance—and the tools available to help you to make your app snappy.

Supplementary Material

A tale of two viewports — part one

A tale of two viewports — part two

Configuring Web Applications

Phantom Limb Vodori

Lesson 10 FAQs

Q: What happens on other kinds of phones and tablets when I use these Apple-specific meta tags?

A: Nothing. The great thing about meta tags, and the reason Apple uses them to trigger Web app mode, is that they won't have any adverse effects or conflict with anything on other browsers.

Q: You mentioned that the device pixel size of iPhone 5 and above is 1136 x 640. What's the device pixel size for earlier versions of the iPhone?

A: The resolution of the iPhone 4 is 640 x 960. Earlier versions of the iPhone (and the iPod Touch) had exactly half the resolution, or 320 x 480 pixels.

Q: In step 5 of the directions in Chapter 4, you replaced the object element with an iframe element. Why?

A: The object element is the correct way to display an SVG graphic. But it has a problem in most browsers: Changing the value of its data property doesn't cause what the browser is displaying to update. My workaround for this was to replace the object element with an embedded webpage containing the iframe element.
The iframe element creates a window inside your browser window, into which you can load another webpage. The JavaScript in Chapter 4 is changing the HTML document that's loaded into the iframe when you swipe on the screen. Pretty nifty, right?

Lesson 10 Assignment

Phantom Limb is a script by Brian Carstensen that makes it possible to simulate basic touch events in desktop browsers. It also displays a huge hand hovering over your browser, which is entertaining by itself!
This is the code for a Phantom Limb bookmarklet. A bookmarklet is a piece of JavaScript code that you store as a bookmark in your browser. When you go to that bookmark, the JavaScript code runs and applies to the current webpage.

Follow these steps to install Phantom Limb:

Highlight and copy the code to your clipboard. Make sure to get all of it, or it won't run correctly.

javascript: void(function(scriptSrc, imgSrc) {var script = document.createElement('script');script.src = scriptSrc;script.type = 'text/javascript';script.addEventListener('load', function() {if ('phantomLimb' in window) {phantomLimb.init({src: imgSrc});} else {console.error('Phantom Limb could not be loaded');}}, false);document.getElementsByTagName('head')[0].appendChild(script);}('https://rawgit.com/brian-c/phantom-limb/v1.0.0/phantomLimb.js', 'https://rawgit.com/brian-c/phantom-limb/v1.0.0/limb-black.png'));

Open a new browser tab in Chrome.

Bookmark the blank tab by clicking the bookmark icon (it's a star) in the address bar. The Bookmark Added pop-up window will appear.

Click Edit in the bookmark pop-up menu. You'll see two fields: name and URL.
Change the name to whatever you like (I recommend calling it Phantom Limb). Replace the text in the URL field with the full JavaScript code from the Phantom Limb bookmarklet. Click Save.
Now every time you want to simulate touch events on a Web page, you can open this bookmarklet, and our friend the giant hand will appear.
Now that you have Phantom Limb installed, let's try it!
Open the version of WatzThis.com that you created in this lesson, or go to www.watzthis.com/L10/watzthis

Click your new Phantom Limb bookmarklet to make the hand appear.

Look at that giant hand!

Now click and drag somewhere in a blank area on the page, in the opposite direction from the direction that the ghost animation is moving. The ghost should switch directions! Play with this for a while!