Cloud Four Blog

Technical notes, War stories and anecdotes

Seven Things I Learned While Making an iPad Web App

Earlier this year I was in the Cloud Four office with my iPad, so I decided to show @grigs what we’d done about orientation change for Lucid Meetings. He looked at it, then got kind of frowny faced and said:

“Do you need to use the browser forward and back buttons in Lucid?”

Naturally, this wasn’t the reaction I was expecting, but I said “Nope! Uh, why do you ask?”

And that’s when Jason suggested that, while the orientation support was fine, we were losing a lot of screen real estate to the fat browser chrome, and wouldn’t it be even nicer to have use of that space?

Thus began my foray into making a “traditional web application” perform double duty as an “iPad web application.”

1. Removing Browser Chrome

So, I wanted to remove the browser chrome, but what that meant was that I actually needed to do the following:

  • tell the browser that Lucid Meetings was “web-app-capable” (yes)
  • tell the browser what kind “web-app-status-bar” to use (black)

I added these lines to the HEAD element:

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

Then I refreshed and… nothing changed. Read, read, read. Oh, I see. I needed to save the application to my home screen by pressing that little icon thing and selecting the Save to Home Screen option (and, I thought, how many users will know to do this???). I relaunched the site from the saved icon and… victory! The browser chrome disappeared. We’re done. Moving on.

Not so fast, bucko.

2. Staying In The Web App

As soon as I clicked any link or button, the web app immediately closed and the site reopened in the browser. That was weird and unexpected. I never did find the exact answer as to why that occurs for internal site links, but it does and there are a couple ways to deal with it.

One way is to convert the site to a single page application with fragment links or AJAX callbacks. That’s exactly how the real-time meeting engine within Lucid works, so that part was golden. The other way is to bind to the click events and prevent the default browser behavior that causes Safari to open (remember, we are in web app, not in Safari, per se). For the multipage, non real-time portion of Lucid, we took the latter approach.

After a bit of hunting around, I found a neat little jquery extension that does what you need: https://github.com/mrmoses/jQuery.stayInWebApp

For various reasons I didn’t want to hook all the links, so I restricted the hook to those links with the “stay” class. Then I added the “stay” class to nearly every link in the application and added the following jquery snippet:

  $(document).ready(function() {
      $(function() {
          $.stayInWebApp('a.stay');
      });
  });

With this jquery extension in place and those “stay” classes added, the Lucid Meetings application now stayed in full web app mode, and that part of the task was finally done.

3. Add to Home Screen

Now the question became “how do I provide a (non-annoying) hint to people to encourage them save Lucid to their home screen?” I normally don’t save web sites to my home screen unless there’s a compelling reason and I never in the past considered that the site might improve its behavior if I did so.

So I went hunting around again and found this little gem: http://cubiq.org/add-to-home-screen

The introduction for this script captures it all:

I found that many iPhone and iPad users don’t know that they can add their favorite web sites to the Home Screen and interact with them like standard native applications. This script helps them to discover this great feature and suggests the steps needed to add your web app to the dashboard.

This script works exactly as advertised and is highly configurable (to reduce the annoyance factor). It also works quite well with the “apple-mobile-web-app-capable” meta tag set to “yes.” That is, when you relaunch as a web app, the script is smart enough not to prompt you, yet again, to save to your home screen.

4. How to Sex it Up a Little

Having gone that far, I now wanted to glam up the web application a bit by adding a startup splash screen and an actual icon for the home screen (to replace the auto-generated screenshot icon). This is a well trod path, though I did have to futz with things a bit. In the interest of putting all the pieces in one place, here are a few more things we added to the HEAD element:

  <link rel="apple-touch-icon" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/images/lm57.png" />
  <link rel="apple-touch-icon" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/images/lm72.png"  sizes="72x72" />
  <link rel="apple-touch-icon" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/images/lm114.png" sizes="114x114" />
  <link rel="apple-touch-startup-image" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/images/startup-iphone.png"  sizes="320x460"  media="(max-device-width: 480px) and not (-webkit-min-device-pixel-ratio: 2)" />
  <link rel="apple-touch-startup-image" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/images/startup-iphone4.png" sizes="640x920"  media="(max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2)" />
  <link rel="apple-touch-startup-image" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/images/lmsplash1004.png"    sizes="768x1004" media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:portrait)" />
  <link rel="apple-touch-startup-image" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/images/lmsplash748.png"     sizes="1024x748" media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:landscape)" />

The first three link elements refer to icons in the standard sizes defined by Apple: 57×57, 72×72, and 114×114. The device selects the icon that’s right for it, with the 114×114 icon working for the non-retina iPad. As you might tell, the Lucid web app mode is also setup for iPhones, though we haven’t yet built our dream user interaction model for handsets. More goodness to come!

The next four link elements refer startup images. Three of them are portrait mode images for the iPhone, iPhone with retina display, and iPad. The fourth is a landscape startup image for the iPad. Note that the sizes here, as shown in the “size” attributes, are absolutely required or the startup image will simply be ignored. Yep, found that one. A couple times.

While trying to get the right startup image to show I saw some references to the associated media queries, so we ended up adding them as well. I didn’t dive all the way in to see if both the “sizes” attribute and the media query are required, but I can say that the above examples all work on their respective devices.

5. How to Keep the Display from Scaling on Orientation Change

At this point we had a pretty nifty full screen web app, but unlike the game of Horseshoes, close enough isn’t good enough — so more tweaking and optimization were called for. In this case, I wanted the application to fit well into the display for both portrait and landscape modes, and I wanted the behavior to feel more like an application than a website.

The starting point for all this activity is to set the viewport meta tag to indicate that the application is sized appropriately for the display and doesn’t need to be scaled THANKYOUVERYMUCH. It turns out, however, that we were not sized correctly. Hmm. Fortunately for us only a minor amount of tweaking was required, so we made a few judicious changes and optimized our application so as not to exclude iPad compatibility. I think of this as mindfulness of design and it’s the same thinking we’ve applied when working on the IE7 user experience (yes, that does matter).

With the layout fixed, we added the viewport meta tag to set the initial scaling. For completeness, I’m also showing the CSS inclusion, which shows that we think in terms of landscape, followed by switching to portrait mode. That’s my desktop legacy shining through. Woot. Don’t worry, it works if you go the other way too. One special note: the “(max-device-width:1024px)” part of the media query is present to ensure this only applies to tablets. There are some technical (read: foreign technology integration) reasons why this needs to be the case, and this isn’t the right place to delve into those, but rest assured we’re drumming those out as well.

  <meta name='viewport' content='initial-scale=1.0,width=device-width' />
  <link type="text/css" rel="stylesheet" media="all" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/css/landscape.css" />
  <link type="text/css" rel="stylesheet" media="only screen and (max-device-width:1024px) and (orientation:portrait)" href="http://3w7ov13ob0hk2kk1w147yffjlu5.wpengine.netdna-cdn.com/css/portrait.css" />

So, we were all done, right? Not quite. With the iPad, an orientation change results in a scaling operation which means text either zooms in or out, which is quite disorienting for a carefully sculpted application! If you hunt around you’ll find quite a discussion about this, as well as some competing recommendations. From my perspective, an application is different than a website where scaling might be expected. Once again, the internet provides a solution in the form of some custom scripting.

The wonderful Stack Overflow captures this discussion and provides a solution: http://stackoverflow.com/questions/2557801/how-do-i-reset-the-scale-zoom-of-a-web-app-on-an-orientation-change-on-the-iphon

  <script type="text/javascript">
    /*
     * This bit of code disables user scaling on iOS until the user tries to scale with pinch/zoom.
     * http://stackoverflow.com/questions/2557801/how-do-i-reset-the-scale-zoom-of-a-web-app-on-an-orientation-change-on-the-iphon
     */
    if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)) {
        var viewportmeta = document.querySelector('meta[name="viewport"]');
        if (viewportmeta) {
            viewportmeta.content = 'width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0';
            document.addEventListener('gesturestart', function () {
                    viewportmeta.content = 'width=device-width, minimum-scale=0.25, maximum-scale=10';
                }, false);
        }
    }
  </script>

As the embedded comment suggests, the script detects that we are on an iPad device and changes the viewport meta tag to disable scaling by setting the minimum and maximum scale to the initial scale. In addition, if the user performs a pinch/zoom gesture (I don’t see this working reliably with double-tap in practice) then we hook the gesture start and “unlock” the scaling capability. In this way, we are pushing our “don’t scale me” agenda, while leaving an option for the user to override our default behavior.

6. How to force a numeric keyboard

Okay, this is a small one, but it DROVE ME CRAZY. One easy thing you can do to say “I love you” to your users is to use HTML5 input types, such as email, url, date, number, and search. In addition to validation possibilities, devices with configurable keyboards may be able to configure themselves with the right keys to speed input. A number field probably doesn’t mean you need to see a traditional QWERTY keyboard.

On the iPad, a “number” input type activates a spinner control that allows you to select from a list. This really doesn’t work, for example, when entering a 16-digit credit card number. For the life of me I couldn’t figure out how to get what I wanted: a simple numeric keypad. It wasn’t until Brad Frost started a discussion on the topic that it clicked for me: add a pattern attribute to a text input field. Voila!

  'pattern' => '[0-9]*

7. Resources Are Available

We’ve only scratched the surface for what we have planned for Lucid Meetings, but what I’ve discovered is we have a vibrant, noisy community of people ready to help. I want to highlight one resource in particular, the Mobile Web Best Practices site, which is a sort of meta resource for me. Grab a beer and check out the resource page. It’ll be a fun afternoon. See you on the other side.

Come Aboard: Inspiring an Empathic Future-friendly Army

This past weekend, Jason and I were fortunate enough to participate in the second installment of "Mobilewood", a retreat-like gathering of hardcore mobile web nerds on Cape Cod. Last fall, we gathered in rural Tennessee to create the Future Friendly manifesto and web site. This time around, we spent some time revisiting the core tenets of Future Friendly and iterating on some of its values.

One of the outcomes of the weekend is the new Come Aboard page, which replaces our original "resources" page. In this new section, we’re aspiring to lay a groundwork of the championing of the Future Friendly concepts. That is, we want to "teach to teach", to build a happy family of Future-friendly mobile web adherents.

We invite you to come aboard the Future Friendly rocketship and be a part of the crew!

Emphasis on empathic peer advocacy

A chief concept of our Come Aboard mentality? Don’t be an asshole. It’s easy to get sucked into the deflating grind of Internet fury and become dogmatic or reactive (or, like me sometimes, retreat altogether in the face of trolls). Instead of taking a rigid stance, we want to encourage thoughtful conversations across teams, across organizations, across the earth.

Of late, I have been in several meetings at large organizations that have similar themes. A dozen or so smart people are sitting around a large conference table, brought in from multiple disciplines in the company to discuss mobile strategy. Each time, I see the two or three developers in the room enthusiastic, simmering with impatience to start hacking away on some of the mobile techniques they’ve recently learned. On the other side of the table, the strategic leaders of the company are also keen to move into the mobile web, but are frustrated with what seems like an invasive, entire overhaul of the company’s infrastructure just to make small steps. The marketing folks, on the other hand, are wary about how to translate their processes and metrics (key analytics that drive the shape of the company’s goals) into this new realm.

So the main question I had in mind while participating in the discussion that lead to Come Aboard was: How can we help all of these smart people communicate with each other?

Future Friendly is a campaign, not a syllabus

One of the criticisms we faced after the first launch of Future Friendly was that the manifesto and site were long on lofty ideals but short on rubber-meets-road tactics. In fact, I recall being one of the vocal ones at our first Mobilewood—I wanted to see more links to more specific examples of how to build this beautiful mobile web of which we spoke.

But the thing is, as Brian LeRoux points out: all specific techniques deprecate—it’s the principles that endure. Our charter is concerned with forging these principles; the implementation(s) will continue to evolve. Not that implementation doesn’t matter. We’ve updated the various pages of the site to link to specific people and content that address how to actually pull this stuff off.

But I realized that Future Friendly’s greatest strength is in its touchstone qualities. A set of core principles, that, when combined with the goals of a project, lead naturally to a set of applicable techniques and technologies. Cool!

Honored to be involved. Let’s go!