arandomurl.com

Coding for the Mobile Web

19th March 2011

Following the beta releases of CouchDB on iOS and Android, I decided to finally jump on the bandwagon and take my hand at building some mobile apps, when it came to native vs HTML there really wasnt much of a decision, Malte Ubl sums up my opinion perfectly:

For the record: Historians will classify native mobile apps as a short resurgence of shareware that was swiftly again replaced by the web – @cramforce

So what was the result? after some fustrating hours I came up with CouchTasks, it is a very basic task manager based on CouchDB however as a work in progress I am quite happy with the result. It is quite obvious that mobile web apps arent going to quite reach the polish of native apps for the foreseeable future, however if you some extra effort you can build something that comes very close to a native experience, is cross platform and takes a fraction of the time. Below I will document some of the tools and techniques I found while building CouchTasks, I found information about mobile web development in general quite sparse so hopefully this can help someone. The code for CouchTasks is all on github

Stating the Obvious

You need to think carefully about your mobile design, mobile devices are much smaller and more fiddly, you need to put plenty of padding on your clickable areas, you should reduce what is on screen and more importantly reduce the the amount of things people interact with in you ui. Mari Sheibley has put up a really useful site that shows some common mobile pattens in action

Another thing to note is that you really need to test your app on a device regularly, while testing inside a small chrome window is certainly helpful, a lot of the issues will only be obvious when testing an a device.

Development Tools

If you havent already (and use android), install the FoxToPhone or ChromeToPhone extension. They just open a url in your browser on the phone to save typing urls.

When I started building CouchTasks it felt like web development before firebug came on the scene, console.log() are available via the android and iphone log viewers but that still leaves a lot of work. Recently however I found Weinre which lets you embed a script into your page that allows you to use the web inspector on your computer to debug pages on your mobile device, there is also JSConsole which uses the same technique to provide a javascript console. These are currently quite fiddly to set up but vastly improve the ability to debug and introspect your web pages.

Position fixed is broken

Due to how mobile browsers scroll the viewpane instead of the content, position:fixed largely doesnt work as expected, the biggest implication is that you can not have a a fixed footer at the bottom of the page, there are various workarounds:

  1. hide your footer when you scroll, position it when you are finished.
  2. put everything overflow:hidden and recreate scroll manually
  3. Redo layout to avoid a fixed footer

Showing and hiding elements on scroll, especially the global constant navigation is clearly undesirable. Given that scrolling is widely used paradigm and very performance sensitive I feel like browser vendors really need to come up with a common solution to this, especially considering that mobile screens are perfectly suited for fixed footer navigation.

If you want to try manually emulate scroll inside a div, iscroll4 has a cross platform script in which you can just specity an element to scroll, I found it wasnt fast / reliable enough though particularly on android.

Page Slide Animations

Sliding between pages is common on mobile and it makes sense so I spend a little while looking into it. There are a lot of loosely tied together articles but I couldnt find a canonical resource so pulling this together took a little time. I experiment by first building using jQuery.animate which is slow enough on desktop browsers let alone mobile devices, I then used CSS transitions where were very easy to swap out over jquery animations but again slightly laggy.

Using CSS transforms combined with CSS transitions look to be the most performant animation as transforms can be hardware accelerated, they are slightly confusing as they dont actually move the dom element just its position when drawn but again its fairly easy to swap between the various techniques.

My technique for animation is to create a wrapper element inside which I put absolutely positioned children

<div id="wrapper"></div>

on the parent wrapper you specify a transition that runs whenever a property has changed.

#wrapper {
  position:relative;
  -webkit-transition: all 0.5s ease-in-out;
  -moz-transition: all 0.5s ease-in-out;
}

when adding a new page, create a new div, place it to the left/right of the currently shown pane, then change the transform on the parent element which kicks off the transition.

var $wrapper = $("#wrapper"),
    size = {width:150, height:300},
    $pane = null,
    currentOffset = 0;

function add(e) {
  // Remove out of view panes from the dom once the transition has finished
  if ($pane) {
    (function(pane) {
      var events = "webkitTransitionEnd transitionend";
      $wrapper.one(events, function () {
        pane.remove();
      });
    })($pane);
  }

  // Calculate position for new panes
  currentOffset += size.width;

  // Create a new pane and place it next to the current pane
  $pane = $("<div class='pane'>yay a new panel</div>")
    .css(size)
    .css({left: currentOffset})
    .appendTo($wrapper);

  // change the transform on the wrapper element, initialising the animation.
  transformX($wrapper, -currentOffset);
};

function transformX(dom, x) {
  dom.css("-moz-transform", "translate(" + x + "px, 0)")
    .css("-webkit-transform", "translate(" + x + "px, 0)");
};

$("#add").bind("click", add);

Here is a working demo (probably chrome / firefox 4 only)

Delay on Click Events

Being responsive is important on mobile web sites, native apps have raised the bar by being smooth and responsive, web apps will be fustrating if they dont live up to the high standards.

On mobiles there is a delay when clicking links and recieving click mouseup and mousedown events. This is in order to handle tap events. I made a quick test here

touchstart   1300546090349
touchend     1300546090448    +99ms
mousedown    1300546090761    +313ms
mouseup      1300546090786    +25ms
click        1300546090794    +8ms

So in this case the click event is recieved almost half a second (445ms) after the touchstart event which is a very noticable delay. There are various solutions: you can quite simply swap out mouseup for touchend, however you need to be aware of the considerations, the user may be scrolling in which following a link would be pretty annoying.

As a quick fix I added this to links where I didnt expect the user to be scrolling, I dont think it would be hard to create a generic pressed event that removes the delay without introducing undesire behavior.

$(document).bind("touchend", function(e) {
  if (e.target.nodeName === 'A' && e.target.getAttribute('href')) {
    e.preventDefault();
    document.location.href = e.target.getAttribute('href');
  }
});

Icon Resolution

Mobile screens are small but often have a very high resolution, I have found icons that looked reasonable on a desktop look terribly unsharp on mobile devices. I plan on looking into SVG support in the near future as the correct solution to this problem, as a quick fix however, serving larger icons and resampling them has worked well for me.

.iconbutton {
    width:16px;
    height:16px;
    background-position:center center;
    background-repeat:no-repeat;
    background-origin:content-box;
    background-size:100%;
    background-image:url(myicon32x32.png);
}

Forms

Laying out forms is alway problematic, however mobile webkit thankfully supports the placeholder attribute so you can replace

<label>First Name</label>
<input type="text" />

with

<input type="text" placeholder="First Name" />

Which places the label inside the input and hides it on focus, saving some valuable space. Mark Pilgrim has documented a lot of new features to HTML5 forms in diveintohtml5 (sadly it looks like required is not supported)

General CSS / Styling

Forms, links and elements with touch/click events are often given additional styling on mobile devices.

-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-appearance: none;
-webkit-focus-ring-color:  rgba(0, 0, 0, 0);
resize: none;
outline: none;

A various combination of these properties will usually get rid of them. its also worth noting that mobile webkit (along with firefox etc) support switching box models, very useful for giving margin / padding to elements that are otherwide full width.

-moz-box-sizing: border-box;
box-sizing: border-box;

Taking a read though the Safari CSS Reference is worth doing.

Phew, finished

If you actually got to the end of that, well done, it got a bit longer than I expected. I will be updating this post as I come across new tools and techniques so please comment on hacker news or get in touch with me via email / twitter if you see something cool / useful.

Comment on Hacker News