When we began working on the New Harvest Mobile Timesheet, we set out some basic tenets that we wanted to guide the project: ease of use, speed and feel.
Of the three tenets, my responsibilities for the project mostly focused on making the app feel nice to use. We love the way iOS feels and wanted Harvest on the iPhone to feel as much like a native app as possible. Building a web interface that feels like a native app is a risky proposition because the closer you get to simulating native behavior, the more noticeable the little differences become (this is the web vs. native “uncanny valley”, if you will). Nevertheless, we focused on a few specific areas that we most associate with the feel of iOS apps: scrolling and animation between views.
Early on, we looked very closely at the Hacker News mobile interface built by Lim Chee Aun. Not only did it work great on iOS, but he took painstaking steps to document the experience in a massive blog post (part 1, part 2) that should be required reading for anyone building a web app targeted at iOS devices. His project didn’t work on Android or other platforms, but we were hopeful that we would be able to use his work as a starting point and bring a lot of that functionality back to Android. However, after building some early prototypes, it became clear that delivering a unified iOS-like experience to all mobile platforms was not going be a worthwhile pursuit.
We decided to change tack and build a framework that delivers a satisfying but more simplistic interface to most mobile browsers. The basic interface doesn’t include things like fixed headers, content panel animations or hidden address bars, but it works in a way that doesn’t make it feel half-assed. If iOS5+ is detected, we enhance the interface to include the missing features and deliver a more robust, native-feeling interface.
We call our new framework Sidetap after the side-based navigation it was built around (the kind of side navigation you can find in iOS apps like Facebook and Sparrow).
Sidetap tries to be useful by not doing too much. It focuses on the hardest problems to solve which leaves you to think about how your content looks and works. These are the things that Sidetap does best:
-webkit-overflow-scrolling: touch to an HTML element that has some kind of overflow set on it. There are some gotchas, but working with this has been pretty nice.
In our case, the element that gets scrolled is nestled three layers deep inside the content panel. Using three divs help stop the browser from scrolling past the element when you reach the bottom of the div. If you’re curious about this technique, you should read this discussion on Github.
All animations in Sidetap are powered by
webkit-animation which run silky-smooth thanks to hardware acceleration built into mobile Safari. We’ve included two types of bi-directional content panel animations to start (slide-up and slide-over), but plan to include more in future releases.
Hiding the Address Bar
We wanted to take advantage of as much of the screen real estate as we could, so that meant hiding the address bar and keeping it hidden. Hiding the address bar is simply done by scrolling the page to the 0 y-coordinate. However, because Sidetap’s main container is set to 100% of the browser window, there wasn’t enough actual content to scroll anything. To get around this, we apply a large amount of padding to the body element on page load and then scroll to 0. After a delay, we reset the container to 100% height and remove the body padding. This gives us a div that’s the perfect window height and an address bar that’s gone away.
Fixed headers should be easy, right? On desktop browsers, using
position: fixed is a reliable way to keep an element in the same position regardless of how a page is scrolled, but fixed positioning wasn’t built into mobile Safari until iOS5. We tried using
position: fixed in an early Sidetap prototype and, unfortunately, the current implementation does not meet expectations (see Remy Sharp’s thorough treatise on all that is wrong with fixed positioning).
Luckily, there was a relatively simple workaround (thanks to the fact that we abandoned fixed headers on non-iOS platforms). To create our fixed headers, we just position them absolutely in the content-panel (which has a non-scrolling height of 100%) and then add the appropriate padding to our scrollable sub-divs. Piece of cake!
Works With the JS MVC of Your Choice
Though we built Sidetap alongside Backbone.js, it is not a requirement and Sidetap could operate alongside any MVC framework of your choice (or no framework at all). Sidetap’s job is simply to take content and animate it — it’s not opinionated about where that content comes from (though it does expect it to follow the basic markup pattern).
Just instantiate Sidetap and store a reference to it. To add and animate to new content, reference the class and Sidetap handles all the fun. Here’s how this looks in a Timesheet view (using Backbone):
Sidetap isn’t perfect and there are a few things that we’ve targeted for improvement:
- Header animation: iOS header animation is surprisingly complicated and Sidetap doesn’t even come close to getting it right.
- Touch events: there is a natural delay in touch events in mobile Safari for which several libraries have been created. Getting one of these libraries integrated would be nice.
- More iPad friendly: The navigation should stay visible on the iPad when in landscape orientation.
Give It a Try
We realize there are no shortage of mobile frameworks available today, but we just didn’t find one that fit our desired style of navigation or didn’t include a lot of bloat (Sidetap is only 2k minified and gzipped). We feel that Sidetap fills this space nicely by trying to do as little as possible (just animate, baby).
We’re releasing Sidetap as an open source project today and we encourage you to try it out and see how it feels. Our sample app shows just how simple switching between content can be. Your contributions, issues and suggestions are very welcome.