Building Mobile Websites
- By Dino Esposito
- Intelligence is the ability to adapt to change.
- —Stephen Hawking
In this chapter:
From Web to Mobile
Development Aspects of a Mobile Site
The Device-Detector Site
A mobile site, much like a native mobile application, is most likely to be consumed by users on the move: people who are standing up, in a hurry, busy, or waiting in line. Under these conditions, users are probably willing to connect to a site using a tiny device because they really believe that they derive some benefit from the site. The site, therefore, must be direct, concise, and accurate.
It is essential that a mobile site should load quickly and allow users to reach all main functionalities in just a few clicks or taps. The user interface should be extremely clear, but also clean and flawless to show the options available at any time, yet still making the act of choosing an option easy. After becoming familiar with the site, users often end up working with it semi-automatically, so even the position of a single button can have an impact on the quality of feedback that you receive. Note that the mobile Human-Computer Interaction (HCI) research field, although new, is very active, and a lot of studies exist about the dos and don’ts of interaction between mobile users and mobile devices and software. Luca Chittaro has a paper that effectively summarizes what mobile HCI means to developers and architects. You can read it here: http://goo.gl/lSG3s.
The previous chapter emphasized the importance of accurately selecting the use-cases to implement. The number of use-cases, however, should be kept small so that the site doesn’t end up as a shrink-wrapped version of the full site. A pragmatic (and then not necessarily exact) rule is that a mobile site rarely needs more than 20 percent of the features available in the full site. I’d even go further by saying that sometimes, not even the 20 percent of features you take from a parent website should not necessarily be reimplemented “as is.” You might want to restructure some of these use-cases and even add new ad hoc use-cases for related scenarios.
A mobile site is a brand-new project that can inherit some code and services from an existing site—more often than not, it inherits large shares of the business logic. This chapter covers a number of issues and open points that you will want to solve before embarking on building a mobile site. After addressing all these points, building the mobile site is reduced to the work of writing a relatively simple and small website.
From Web to Mobile
You rarely build a mobile site without also having a full site in place. Most of the time, you build a mobile site to serve mobile users better. In some cases, you start building both full and mobile sites at the same time. Currently, it’s quite unlikely that you build a mobile site as a stand-alone project. Whatever the case may be, however, this section aims at isolating the issues that differentiate a mobile site from a full website.
If you’re building a mobile site as a spin-off of an existing website, then the chances are good that you will be able to reuse large portions of the existing application’s back-end code. Those include the data access layer, the domain layer, and possibly a bunch of other distinct components (such as services and workflows) that you may already have in place, which will provide bits and pieces of business logic. If you can replicate some views without too much modification, you may even end up being able to reuse webpages and ASP.NET Model-View-Controller (MVC) controllers—more generally, parts of your presentation and application layers.
As you move towards the presentation layer, though, the chances of reuse diminish. How would you deal with scripts, images, style sheets, and markup? For images and style sheets, there’s probably an easy answer—you just have to reduce their size. For scripts and markup, the answer is less obvious and likely is influenced by context.
Before the community of web developers (re)discovered AJAX a few years ago, websites were always built as a navigable collection of distinct pages. Jumping from one page to the next required links and forms. The browser handled each request, which resulted in a full replacement of the current page.
AJAX changed the course of things by using the services of a small browser-hosted component—the XmlHttpRequest (XHR) object—through which your script code can play the role of the browser and conduct server requests autonomously. The net effect is that webpages can contain ad hoc script code that use XHR to download data or partial pages. After being downloaded, the content is processed by some other script code and used to update the currently displayed page. AJAX can be used for some specific (perhaps even critical) features, or it can be used extensively throughout the site. When that happens, the site architecture is usually referred to as the Single-Page Interface (SPI) model.
The Single-Page Interface Model
In brief, the SPI model refers to a web application that behaves more or less like a desktop application—it has a primary user interface (UI) layout that is adjusted and reconfigured via AJAX calls. The page downloads everything it needs from the source site via script-controlled actions. The SPI model has been recently formulated as a manifesto. You can read about it here: http://itsnat.sourceforge.net/php/spim/spi_manifesto_en.php.
In addition to script, SPI requires helpers for data binding and UI refresh, which adds a few more tens of kilobytes. Popular libraries in this segment include JsRender, JsViews, Knockout, and Upshot.
Personally, I wouldn’t adopt the SPI model without first performing deep analysis of the context. The main challenges with an SPI implementation can be summarized as follows:
In case of intermittent connectivity, it’s difficult to figure out whether the problem is with the application or the network. This may be frustrating. Not that this same problem doesn’t exist for other models (i.e., the full-page refresh model), but at least tiny, non-SPI pages download well, even with limited bandwidth. Moreover, with no connectivity at all, you immediately grasp the nature of the problem—when nothing shows up, the problem is not the application.
Many sites require users to log on before they will serve content. If the users’ session expires, the full-page refresh model redirects them to the logon page at the first successive access. The problem is both manifest and easily resolved. With an SPI site, although user authentication is also AJAX-based, it may take hours before you figure out the root cause of the misbehavior you’re observing. In SPI, user authentication requires due attention and effective client and server-side implementation to work smoothly.
So let’s explore some other available options.
Full Page Refresh
At the extreme opposite of SPI lies the classic Full Page Refresh (FPR) model. FPR is how the web worked for years: the browser makes a request for a new page, the web server returns the new page, and the browser replaces the current page with the new rendered content. This process occurs repeatedly for each user action.
AJAX (on which SPI is heavily based) made the classic FPR web experience much less compelling, and it also made it more natural for users to expect that only fragments of the current page would be updated as the result of a given action. In a desktop scenario, the FPR model is cumbersome, so more and more large sites are progressively adding AJAX-based capabilities.
However, the significant impact that FPR has had on desktop sites (which have large displays and numerous auxiliary resources for downloading, caching, and refreshing content), is less so on mobile sites because mobile pages are considerably smaller and lighter to begin with. Still, loading several small pages may still be less engaging than updating bits and pieces of the currently displayed page. Updating the current page may still be slow over a slow connection, but at least it doesn’t have a dramatic impact on the user experience.
Partial Page Refresh
Some middle ground between SPI and FPR can be found in the partial rendering that both ASP.NET Web Forms and ASP.NET MVC support. In terms of traffic, partial page refresh (PPR) falls between the two extremes—it is not as efficient as SPI, but it’s not as poor a user experience as FPR. The idea is that the browser places a request as usual, but that request is captured at the script level—via embedded script—and silently transformed into an AJAX request.
On the server side, the web server handles requests as if they were regular full page requests, but the response is packaged as an HTML fragment. The data being transferred is a mix of data and markup—just the delta between the markup of the current page and the requested new page.
The benefit of the PPR model is that it offers many of the benefits of AJAX without the cost of having to learn new programming features. In ASP.NET Web Forms, PPR happens relatively automatically through the UpdatePanel control; in ASP.NET MVC, it occurs through the Ajax.BeginForm HTML helper.
In a nutshell, using PPR means that an FPR approach won’t require special skills on the development side. In contrast, an SPI model may represent a complete paradigm shift for many developers. PPR represents some middle ground.
Context Is King
Which of the previous options is preferable? There’s no obvious and clear answer. If you’re determined to find just one answer, then the best approach depends strictly on the context and the knowledge that you have about the devices that are going to access your site. If smartphone traffic is predominant, you definitely can opt for SPI. But if you’re interested in reaching the widest possible audience, then you probably should opt for FPR.
The point, though, is that there’s probably no ideal solution that works in all cases. Mobile devices are so different that you really should consider partitioning your audience into a few distinct classes of devices and arrange a different solution for each. That could mean serving plain HTML pages to older browsers while implementing a nicer SPI solution for smartphones.
The jQuery Family of Libraries
Note that jQuery is required even if you plan to use only jQuery Mobile, which offers a variety of ready-made components for scaffolding a mobile site. Plug-ins for jQuery Mobile can put a “skin” on your mobile site so that it looks like a native application with animations, navigation effects, and snazzy presentation.
Microframeworks are small, highly focused libraries whose overall size is often only a few kilobytes; sometimes even 1 KB or so. There’s no magic and no special tricks—microframeworks are so small not only because they are minified and gzipped, but also because they take on just one or two tasks.
You probably will want to pick up a library for asynchronous (async) loading: one for optimized DOM traversing, one for touch gestures, and perhaps a few more. You can find an interesting list of such microframeworks at http://microjs.com; their average size is around 1 KB.
Application Device Profiles
Device fragmentation is huge in the mobile space. If the differences between browsers in desktop site development scare you, then be aware that the mobile space is much worse.
On rare occasions, you can get by with just one set of pages for a mobile site. Ideally, you need pages that can adjust intelligently to the characteristics of the requesting browsers. Sometimes you just end up having multiple versions of the same page—one for each device (or class of device) that you intend to support. Alternatively, sometimes you may have one common page template that you fill up with device-specific content. But at the end of the day, these are implementation details.
The crucial point is that you need to split your expected mobile audience into a few classes. Then, for each page or view, you provide class-specific markup. This is the essence of multiserving, as briefly described in Chapter 3, “Mobile Architecture”, Chapter 6, “Developing Responsive Mobile Sites”, will illustrate multiserving with an example.
Practical Rules to Class Profiles
In the mobile space, neither the team building a given site nor the team producing a general-purpose library can afford optimizing pages on a per-device basis—the number of potential devices to take into account is just too large (in the order of several thousand). Hence, a common practice has become to classify all the devices you’re interested in into a few classes. How many classes do you need to have, and how do you define a class?
A device class typically gathers all devices that match a given set of capabilities. You define the classes based on the business cases and scenarios. A basic (but still arbitrary) classification may consist in splitting the whole range of requesting devices into three categories: smartphones, tablets, and all other browsers. You provide a rich web experience to smartphones, serve the full site to tablets, and offer plain HTML to all others.
How would you define a smartphone? Everyone would agree that an iPhone is a smartphone while, say, a Nokia 7110 is not. [The Nokia 7110, released in the fall of 1999, was the first device equipped with a Wireless Access Protocol (WAP) browser.] In contrast, the Nokia 6600 certainly was a smartphone when it came out in 2004, but nobody would consider it a high-end phone today. But there are no hard and fast rules. You should know that not only the device classes, but also the rules that determine which class a given device belongs to, are highly variable and strictly specific to a business scenario. At the same time, this lack of fixed rules and practices makes it possible for everybody to define classes in a way that best fits a given business. All you need is a reliable infrastructure that first identifies the device and then tells you about its real capabilities. I’ll return to that infrastructure in a moment.
As a purely intellectual exercise, here are some requirements that identify a modern smartphone in 2012. Note that these are likely to change, even in the near future.
Operating system (minimum version): all versions of iOS, Android 2.2, Windows Phone 7, RIM OS 6, Samsung Bada 2.0, Symbian Anna, and Nokia Meego
Input mode: touchscreen
Screen size: 320 x 480 pixels
Admittedly, this definition is rather arbitrary, and it may sound too restrictive for some while being way too relaxed for others. Above all, this definition will become progressively less pertinent as more powerful devices hit the market.
A tablet has two main characteristics—it is a mobile device (not a desktop browser), and it has a larger screen than a smartphone. You can probably set the lower boundary to 640 pixels today.
It is important to note that grouping all the remaining devices into a single class may be a tough decision. Whether you really want to serve plain static HTML to all of them or further split the remaining devices into two or more classes is up to you.
How can you discover the capabilities of the browser for each device? How can you be sure that the requesting browser is really a mobile device? If it’s sufficient for your needs to just check the screen size and screen resolution, then you might decide to go with CSS media queries for high-end browsers, and use script code that simulates that on older browsers. Although this approach may work in some cases, it’s not a route that will take you far. Instead, relying on a commercial device description repository (DDR) is probably the best way to go. Chapter 6 discusses a few DDR frameworks, focusing in particular on WURFL.
Dealing with Older Browsers
When I talk to executives planning the mobile strategy of their companies, I often get the impression that when they say “mobile,” they just mean the iPhone and iPad. While it can’t be denied that iPhones and other smartphones are actually responsible for most of the mobile traffic to sites, the mobile universe contains many other types of cell phones and devices as well. Unfortunately, not all of them have the same characteristics, but they are so numerous that you must find a common denominator approach.
In the process that you use to identify the device profiles to support, you must define the bottom of the stack at some point. Devices that fall into this sort of catchall group typically are served plain HTML or, at least, the simplest markup that your mobile site can serve.
What’s the best way to handle this?
When you end up having a catchall device profile, it also means that there’s some rich library you’re relying on for higher-end devices. The jQuery Mobile library is an excellent example. Such mobile libraries sometimes offer to scale down the otherwise rich markup they produce on older browsers automatically.
That’s apparently a fantastic deal for you: you write the mobile markup once, and it gets downgraded automatically for less powerful browsers. Unfortunately, my current experience has not been particularly positive on this point. Although most libraries do fulfill their promises of downgrading the markup, the quality of the HTML that they produce when that happens is often below your desired standards. You probably want to take care of the HTML being served to older devices yourself rather than blindly relying on the kind of hard-coded markup served by some libraries.
The bottom line is that while jQuery Mobile (and other libraries) can truly downgrade HTML based on the requesting browsers, you’ll achieve a better final effect if you manually fix up the output. Currently, I’m inclined to use jQuery Mobile—but only to serve smartphones and tablets.
Optimizing the Payload
Minimizing the number of HTTP requests to websites is always a good thing, and it should be a central aspect of any strategy aimed at improving the performance of a site.
If you have ever tried to use a mobile device to connect to a very basic site with a few plain HTML pages, a bit of CSS, and one or two images over a 3G data connection, you have experienced a delay, or latency. This latency is relevant if the device is not one of the latest smartphones with a powerful processor. In the mobile space, minimizing the total amount of data transferred and the number of requests is not simply a matter of optimization; it is a crucial development point.
Over the years, a number of recommended practices have been worked out to help developers build fast websites. Yahoo! has been quite active in this field, publishing a very valuable document that you can read here: http://developer.yahoo.com/performance/rules.html. The rules in that document are written for a generic website, but for the most part, they can be applied equally well to both desktop and mobile sites. Here’s a summary of the key suggestions:
Take care of the page structure and find the right place for scripts and style sheets.
Reduce the number of HTTP requests.
Reduce the size of resources.
Maximize the use of the browser cache.
Let’s briefly go through the optimization aspects that are most relevant to mobile sites next.
The Page Structure
A mobile browser may load pages significantly slower than a laptop browser. This means that not just raw performance but also perceived performance is important. Little tricks, such as placing style sheets at the top of the page in the <head> section help, because doing that means that the body of the page will be ready to render as it is downloaded. The overall download time doesn’t change, but at least users see some results a bit sooner.
Similarly, placing scripts at the bottom of the page is helpful because it reduces the impact that synchronously downloading scripts may have on page rendering. When browsers encounter a <script> tag, they stop page rendering and proceed to download the script synchronously. Page rendering resumes only after the script files have been downloaded, parsed, and executed. When all the scripts are at the bottom of the page, browsers don’t need to interrupt the page rendering process to load scripts; therefore, browsers are free to concentrate on displaying an early view of the page.
Reduce the Number of Requests
Too many HTTP requests are the primary cause of latency in websites. This statement is even truer for mobile sites. Executing an HTTP request is an expensive operation, especially when that entails connecting to a radio cell. In this case, to preserve battery power, the device sometimes cuts off the connection right after receiving the HTTP response, meaning that to execute another request, a new handshake is required, which consumes both time and resources.
For this reason, it is doubly sinful to let links to duplicate resources go unnoticed. Linking a script twice doesn’t affect the rendering of the page, but while the performance hit is negligible on a laptop, it becomes a serious performance hit in a mobile scenario.
The same can be said for redirects. Each redirect requires two HTTP requests. Avoiding redirects from a site is one way to reduce the number of requests that devices visiting that site have to place. Most ASP.NET MVC books [including my book Programming ASP.NET MVC, 2nd ed. (Microsoft Press, 2011)] recommend that the Post-Redirect-Get pattern is appropriate for input forms because it saves applications from unwanted F5 refreshes. In a mobile space, that also introduces extra requests; make sure that you make a sound decision about your projects on this point. If you can afford to use AJAX, that would probably be an ideal compromise.
When your goal is to reduce the number of HTTP requests, there’s little better than merging two or more files. Image sprites, for example, illustrate just this point. A sprite is an image that results from the concatenation of two or more images. That way, the browser can make a single request, downloading and caching multiple images at one time.
Image sprites are not always ideal. Using sprites works great with very small images, such as button icons that are widely used across the pages, but sprites may not be as ideal for the relatively large images used by distinct pages. Downloading a 50 KB image may not be easy over a 3G connection and with an older browser, so if the image is part of a sprite and the sprite size is 100 KB or more, downloading it would take even more resources—probably enough to make the user experience unpalatable.
Sometimes, to save an HTTP request, you can decide to encode a small image (one on the order of just a few kilobytes) as a Base64 string and embed it directly in the page. The data Uniform Resource Identifier (URI) scheme just serves this purpose.
The data URI scheme defines a standard for embedding data within the page instead of linking it as an external resource. The scheme is defined in RFC 2397; you can read about this RFC on Wikipedia at http://en.wikipedia.org/wiki/Request_for_Comments. The net effect of applying the data URI scheme is that the content of the src attribute of the <img> element matches the following template:
data:[<content-type>][;base64],<bytes of the image>
First, you place the data keyword followed by the Multipurpose Internet Mail Extensions (MIME) type of the image. Next, you place the Base64 keyword followed by the Base64-encoded representation of the binary image. If you were embedding an image manually, here’s the markup you would need:
<img class="image" src="data:image/jpg;base64,/9j/4AAQSkZJRgA..." alt="" />
The Base64 image encoding (also known as image inlining) saves a few HTTP requests and improves both the real performance and perceived performance of the page. It is not a feature to use for just any image and page!
Improve Your Control over the Browser Cache
If the primary objective of a mobile site is to minimize the number of requests, browser caching is the primary tool that you have to manage. Moving auxiliary resources (i.e., style sheets and scripts) to external files often helps. Initially, the number of HTTP requests is higher, but after the first access auxiliary resources are cached, no more requested expiration occurs.
External resources are really beneficial if such resources are widely referenced from a variety of pages. In home pages and rarely visited pages, inlining of resources (where possible) may be a better option. In addition, you can drive the browser behavior about caching by using e-tags and Expires headers on your critical resources.
The browser cache also applies to AJAX responses. The use of AJAX makes the request go unobtrusively for the user, who remains in total control of a still responsive page. However, it doesn’t mean that the request will end in a matter of milliseconds. Sometimes caching the AJAX response helps to make most responses really instantaneous. This pattern, however, doesn’t work for all types of requests. If you place a request to read the current balance of an account, you don’t want it to be cached. If you use an AJAX request to auto-complete a text field, you want to cache as much as possible. This is to say that control over the AJAX cache must exist, and in real-world scenarios, it must be applied on a per-URL basis. Most libraries, though, offer an all-or-nothing control, which is hardly the right thing for a mobile site.
The Offline Scenario
A mobile site represents an excellent shortcut to implementing a mobile strategy because it brings products and content to a variety of devices without writing a different application for each mobile platform that you intend to support. At the same time, a mobile site requires constant connectivity to work well. This aspect of mobile sites is going to be more and more of a showstopper for sites, and it highlights the key difference between mobile sites and native applications. It’s not coincidental that offline applications have been given a role in using HTML5.
Offline Sites with HTML5
An offline experience without an HTML5-enabled browser is quite hard to achieve; while it’s not impossible, it does require a strong commitment. In other words, it’s not a feature that you would want to offer as a free add-on to a customer!
When most people talk about offline sites, they mostly mean online sites that perhaps occasionally experience long downtime periods. The key to surviving such lack of connectivity is caching—in particular, to take advantage of the browser’s ability to cache resources that a user may navigate to later, during a downtime window. These resources include not only auxiliary files, but also AJAX responses.
HTML5 lets you create a manifest file and link to it from the <html> tag of the home page. In this manifest code, you list the files you want to keep cached, which resources are a fallback for other (possibly missing) resources, and which resources are available only while online:
<!DOCTYPE html> <html manifest="/offline.appcache"> ... </html>
The browser’s ability to cache a subset of the full site on the client isn’t a great thing, per se. It requires more than that to be truly effective. That means is that there is little value for users in just navigating through a few static pages. While that’s considerably better than getting a 404 error message from the browser, it’s not really a decisive change.
Persisting Application Data
Persisting application data locally is another aspect of websites strictly related to surviving an offline status interval. In an HTML5-enabled browser (again, most browsers in today’s smartphones are HTML5-ready), you use the local storage application programming interface (API) to write name/value pairs in an application-restricted area managed by the local browser. In the near future, the flat name/value format may become even more sophisticated and evolve into a table-based and indexed format.
Persistence is also related to synchronization. The ability to persist data locally fully enables occasionally connected application scenarios. At the same time, in an occasionally connected scenario, you might want to offer a read-only view of the data or enable updates. When this happens, you have either the problem of queuing operations or the problem of editing a local cache of data to be synced with the server when the connection is re-established.
Overall, if you want to build a full-fledged, occasionally connected scenario, you’d better endow yourself with a solid sync framework and/or consider using the OData protocol and facilities for your data exchange.