Site Meter

Full-height app layouts: Animated transitions within panes

In the previous post, I showed a simple yet very useful and robust CSS technique for creating full-height layouts for web-based applications. To recap, it means you can subdivide both the width and height of the screen into a arbitrarily nested set of panes, each of which can scroll independently. This is useful whether you’re building apps for desktop browsers, for tablets, or for phones.


Not amazingly exciting just yet, but there’s more… :)

One of the other reasons for defining pane positioning using those particular CSS rules is that it becomes trivial to have multiple different content panes that can populate any given pane container, then to change which pane is visible within a container, and even to animate the transitions during those changes.

For example, here’s a layout involving a fixed header, a fixed footer, and two scrollable body regions (laid out using the same CSS rules as defined in the previous post):

<div class="header row">
    <h2>My header</h2>
<div class="body row">
    <div class="first pane scroll-y">
        <p>This is the first body view</p>
    <div class="second pane scroll-y">
        <p>This is the second body view</p>
<div class="footer row">
    <p>My footer. Could put icons here.</p>

This will lay out as follows, with the first body pane and second body pane occupying the same area on the screen:


Then, you can trivially switch between the two body panes just by controlling their visibility (e.g., by using $(".first.pane").hide() and $(".second.pane").show()).

Animating the transitions

Instead of just hiding and showing panes instantly, you can cause them to fade in/out or even to slide in and out. This pretty well replicates an aspect of the UI experience familiar to users of touch-based smartphones and tablets.

However, JavaScript-based animation mechanisms (such as $.animate in jQuery) aren’t as smooth as I’d like. They tend to give low frame rates, as the browser has to run custom JavaScript to compute the positions of elements for each frame. Fortunately since we’re controlling the layout purely using CSS, it’s both easy and robust to use pure CSS 3 animated transitions, giving silky-smooth results on devices that support hardware accelerated CSS transforms (e.g., iPhone and iPad), exactly like a native application.

To make this easy to reuse, I created a small bit of JavaScript boilerplate (about 1kb gzipped) that exposes functions for triggering pane transitions, being sure to take full advantage of hardware acceleration where available. For example, you can write:

// Initial pane visibility
// Navigation between panes
$(".first.pane button").clickOrTouch(function () {
    $(".second.pane").showPane({ slideFrom: 'right' });
$(".second.pane button").clickOrTouch(function () {
    $(".first.pane").showPane({ slideFrom: 'left' });

… and then if you click any button in the first body pane, the second body pane will slide in smoothly from the right, and vice-versa. Note that although this code uses looks as if it uses jQuery, it doesn’t – it actually uses XUI instead (a very lightweight JavaScript framework that implements a fraction of the jQuery API in a fraction of the space), but you could equally do similarly with jQuery.

The boilerplate code offers the following transitions:

  • slideFrom – causes the target pane to slide in from the specified direction, and simultaneously the current pane to slide out in the opposite direction
  • coverFrom – causes the target pane to slide in from the specified direction. The current pane stays still, getting covered over by the target pane.
  • uncoverTo – causes the current pane to slide out in the specified direction, revealing the target pane underneath
  • default – instantly shows the target pane and hides the current pane

… and it works on IE7+ (including WP7 Mango), iOS, Firefox, Chrome, Safari, Opera, and probably others. For browsers that support hardware-based CSS3 transforms, like Safari on iOS 4+, it will be used and is impeccably smooth; others will use unaccelerated CSS3 transforms, and for those that don’t support CSS3 transforms, it falls back on JavaScript-based animation.

Also notice the “clickOrTouch” event – on browsers that support touch events (e.g., iOS Safari), this fires the instant your finger comes into contact with the screen (and hence is noticably faster than a regular click), whereas on non-touch devices, it’s equivalent to a regular click (i.e., when you release the mouse).

Runnable examples

Here’s a phone-styled example just showing how you can transition the contents within a given pane, or you can transition the contents of the entire screen. Note that this is an iframe you can interact with, not just a pretty picture :)

Also: Run full screen (e.g., to try it on a phone)

Similarly, here’s a tablet-styled example showing how transitions work just the same in arbitrary sub-panes as well.

Also: Run full screen (e.g., to try it on a tablet device)

Note: To be clear, I’m not starting a new open source project here. These are experiments in mobile-friendly app layouts – I’m blogging the results just in case it’s useful to someone else! In the next post, I’ll focus on managing navigation history within each pane, so you can easily let a visitor go “back” and “forwards”.

14 Responses to Full-height app layouts: Animated transitions within panes

  1. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #958

  2. This is fantastic Steve! I must say that I always enjoy your work. I am eager to read your next article about handling state during the transitions. This type of layout could probably translate smoothly to a phonegap implementation.

    Thanks Steve!

  3. Sanat Gersappa

    Great post. Curious to know what tool you use to create those nice blue wireframes.

  4. Joel

    I don’t think this worked in Firefox 5.0.1.

  5. Good stuff, exactly what I’ve been looking for today but this didn’t seem to work out that well for me. Are you aware of any existing alternatives?

  6. Dirk

    Very useful stuff! Not just for mobile, but making browser-applications feel more app-like. Company I work for loves the ‘app-feel’ :)

    So thanks for posting your explorations!

  7. Pingback: Full-height app layouts: Navigation and History - Steve Sanderson’s blog - As seen on YouTube™

  8. Plamen Penchev

    Thanks! Full-height app layouts blog posts are really useful. :)

  9. zbrong

    Great job!
    I’v copy your code and have a try , but it dosn’t work, if any other js needed?
    would U code a panes.js and make it no need other js except jquery ?
    thank U !

  10. We are a bunch of volunteers and opening a brand new scheme in our community. Your website provided us with helpful information to paintings on. You have performed a formidable process and our whole community will be grateful to you.

  11. Tej

    I read about this full height layout technique a while ago and remember thinking it was a neat idea, and I’ve finally had a bit of time to try using it while making something.

    I’m having one issue. If I put a jQuery datepicker within div.body, the datepicker position doesn’t update when div.body is scrolled, instead it stays stuck in place. I was wondering if anyone has had the same issue or found a workaround for this?

    P.S. If I change my code so that the header and footer are position: fixed instead of absolute and I then remove position: absolute from div.body but instead add a top margin the height of the header and a bottom margin the height of the footer, then I still get a full height app with the scrollbar running down the full height of the window. But I can do this because I don’t need multiple scrolling panels within body, I just need body to scroll with the header and footer always visible.

    P.P.S. Knockout looks great! Just about to try that now too.

  12. leecd

    Ninject with derived type doesn’t work!

    in book p.135:
    ninjectKernel.Bind().To().WithPropertyValue(“ItemLimit”, 200M);

    ShoppingCart cart = ninjectKernel.Get();

    can’t work!

    The runtime reports LimitsShoppingCart’s ItemLimit property is null.

  13. leecd

    Ninject with derived type doesn’t work!

    in book ‘Pro ASP.NET MVC3 Framework’ p.135:
    ninjectKernel.Bind<ShoppingCart>().To<LimitsShoppingCart>().WithPropertyValue(“ItemLimit”, 200M);
    ShoppingCart cart = ninjectKernel.Get<ShoppingCart>();

    can’t work!

    The runtime reports LimitsShoppingCart’s ItemLimit property is null.

  14. leecd

    It does work!

    When refactor the ShoppingCart class, define an automatic variable Product[] products in constructor, then the class variable products can’t be assigned.

    so the runtime report error. then i take it as ItemLimit wrongly, in fact that the products is null.

    thanks for your book.