Bookboard – A Model for the Future of the Web

One of the missions of PhoneGap has always been to bring about its own demise. The PhoneGap team wants the web to have all the functionality that we currently enjoy on devices so that there isn’t a need for PhoneGap to exist. It’s one of the reasons I love the project; I think that’s the perfect goal. I hope we get away from app stores and back to a world where the web rules all. There are obviously many things that have to happen before that becomes a reality but every once in a while I see a glimpse of what the web could be if that vision comes to pass. The latest iteration of that is Bookboard. (Sign up here)

Book Board Selection Screen

Bookboard is a web app that was written for the iPad. It makes heavy use of iOS specific features that allow websites to add themselves to the home screen for a full-screen experience and provide specific icons so that to the end user, it kind of feels like an app that just didn’t come from the app store. Even though it’s iOS-specific right now, the UI design is such that it would work across platforms. So many apps, even PhoneGap apps, follow the specific list->detail form that brings a lot of baggage with it. You have to work at making sure your list/detail view works the way it’s supposed to on iOS or Android (or other platforms). But Bookboard has a very design-heavy UI that lends itself to any platform. The books intuitively ask to be swiped from side to side as you are looking through them (with a nice parallax effect in the background) and when you go into the book itself you use the same swipe motions you would expect. It’s list-detail but brought to life in an interactive way.

Reading a Bookboard Book

Bookboard also makes use of hardware acceleration of CSS for many of its transitions. Everything on my iPad 2 is incredibly fluid and it’s difficult to tell that it’s *not* native. One of the things many app developers have to deal with is making their content feel native without it actually being native. The Bookboard approach seems ideal to me. They’re using a UI that hasn’t been replicated by every other app so they get a bit of leeway in terms of performance, but they don’t need it because they’re offloading to the device hardware via CSS. It works out very well.

Bookboard Menu Screen

Beyond the tech side Bookboard is simply a beautiful, well-designed app. It’s meant for children to read (and they can unlock achievements for reading more books) so it has to be intuitive, but it also looks great. Attention to detail like the parallax scrolling add a friendly touch and my daughter loved the app. She knows how to use an iPad and scrollable books, friendly gestures, and words that are magnified on touch all came naturally to her. If you’re a parent with a kid who enjoys reading (or you want them to enjoy it more) Bookboard is well worth a try.

This is how I want the mobile web to look and behave. Bookboard leverages the mobile-app centric parts of iOS to create an app-like experience while still retaining the unique, design-centric approach that has made the web so great. It’s this kind of custom UI and design influence that starts to make developers stop and think about whether they go native or web. A basic list-centric app isn’t that tough to do in native so more often than not, it probably makes sense just to go native. But the kind of custom UI and design that Bookboard uses lets you involve the designers much more deeply in the process. Since most designers (should) feel comfortable with CSS, they can jump in and contribute directly to the end result. If you can get performance like this using web technologies, I think it becomes a tougher sell to try and do native when web gets you more platforms, more reach, more designer input, and more deployment flexibility.

Hopefully in the next couple of years apps will have been replaced by experiences like Bookboard. It would make my home screen a much more interesting and beautiful place while giving developers ultimate flexibility. That’s a big win for the web. I encourage you to go sign up and see what I mean.

Slides on New CSS Features

I spoke with Ray Camden at the Grand Rapids Web Developer/Designer Meetup this week on some of the new CSS features that Adobe has been working on. The event went well, Ray did an awesome job and hopefully I didn’t stumble through the CSS parts too much.

I’ve posted my presentation on GitHub for anyone who is interested. It’s high-level but shows off how to use some of the new features and shows them in action. To view the demos you’ll have to have Google Chrome Canary with the Experimental Webkit Features flag enabled. And the last part requires a prototype Webkit build from Adobe. If you have any feedback, let me know.

Using Ratchet with PhoneGap

When I saw the Ratchet project I was stoked. While the initial site talked about being able to prototype iPhone applications with HTML/JS/CSS it was pretty apparent that this could be something even bigger than that. And sure enough, on their README page it talks about long term goals:

We eventually want to extend Ratchet beyond the prototying for iPhone and create HTML/CSS/JS components for iPad and Android devices. Our dream is that Ratchet becomes the best way to create mobile experiences with web standard languages.

To me, that means this could be a great project for PhoneGap applications. So I threw it into a project and looked at getting it running. Unfortunately nothing happened. I could get some components to work but once I tried to move between pages it wouldn’t respond. I tracked it down to the push.js-esque functionality that they’re using. Specifically, it’s a single line of code that causes issues.

if (xhr.readyState == 4) xhr.status == 200 ? success(xhr, options) : failure(options.url);

The issue is that PhoneGap only seems to return a status of 0 when using XMLHttpRequest. I’m fairly sure this has something to do with the fact that it’s loading from the file system and not a server, but I’m not 100% sure. By making sure that Ratchet accounts for status of 0, page transitions work perfectly.

if (xhr.readyState == 4) xhr.status == 200 || (xhr.status == 0 && options.url.indexOf('file:///') != -1) ? success(xhr, options) : failure(options.url);

I’ve got the full project up on GitHub and you can bring it into PhoneGap Build and test it yourself. I’ve only tested it on iOS but it works pretty damn well. I’m definitely intrigued. I’ve also posted this to the Google Group to see if they can support this out of the box.

Update: Simon mentioned in the comments below that by tweaking the code to check for status 0 AND file system, it would be safer. So I modified the ratchet.js file in my project to take that into account. Thanks Simon.

Experimenting with CSS Exclusions

Okay, this is going to be scattered and on the cutting edge side, so buckle in. Adobe has been hard at work making the web a little bit richer when it comes to how type is displayed. A great example of that is CSS Regions, which let you create linked islands that text can flow between so you have a lot of control over how text gets laid out on the screen. That’s currently in the “Canary” builds of Chrome and if you go to about://flags and turn on “CSS Regions” you’ll be able to view the demos. The other thing we’ve been working on is a bit further out, but it’s in the same vein. It’s called CSS exclusions. It essentially lets you create more interesting islands of text in the form of shapes that text will flow around. At this stage it’s still very, very early. In fact, the only way to test CSS exclusions content is with a special build of WebKit that’s available on Adobe Labs.

The Backstory

A lot of the demos associated with these features are associated with magazines, and especially with the iPad 3 coming out, it’s going to be critical to be able to build expressive content that scales. Since magazines are mostly text, expressive text will be a big deal. I’ve been mulling over doing a beer-related magazine and figured it would be cool to try out some of the CSS demos to create something that might look unique and fit in a beer magazine. So I thought “hey, I could create shapes of different beer glasses and run text through those!” That was the basic premise. As I dug in, I found a couple of caveats. Most I’ll get to throughout the post, but the biggest one is that there currently isn’t a version of WebKit that has both CSS Exclusions and support for flowing across CSS Regions. So my original idea ran into a small roadblock but I’ll be able to fix that down the road.

Creating regions

The CSS Exclusions spec supports SVG’s basic shapes. That includes circles, rectangles, and polygons. At this point it can’t do arbitrary path data but you will be able to use SVG data according to the spec. So I started with creating the various types of beer glasses in Illustrator with the polygon tool. Then I had to set up the glasses on the page and make text flow correctly. The standard method seems to be to create two CSS classes, one for the properties that every region or shape will have, and another class for the specific region, in this case, glass type. I called my main region container and it looks like this:

     .container{
          position:absolute;
          height:500px;
          width:300px;
          text-align:justify;
          margin-top:0px;
          font-size:10px;
 
          -webkit-wrap-shape-mode: content;
          -webkit-render-wrap-shape: none;
          -webkit-hyphens:auto;
     }

The main properties are those three on the bottom. The first one tells the browser what I’m doing, and that’s wrapping the content within a shape. I think the other option here is around, which would make the shape an exclusion but I don’t think that’s working in my build of WebKit (or I’m doing it wrong). The render-wrap-shape is good for debugging as it shows you an outline of the shape so you can see how it’s appearing. I found this incredibly helpful as I laid objects out on the page. The last one, hyphens, lets you tell the browser how you want it to break up text. If you go for none there, it will only flow full words within the content. Otherwise it fills the content as much as it can before breaking words with a hyphen. For fuller-looking shapes, go with hyphens set to auto.

Next I had to set up the specific glass shapes. The hardest part for me was lining things up correctly. The way I created the polygons I think made it tougher to lay out. It also doesn’t change as you resize the page because I’m not using percentages (if that’s even possible with polygon objects). It looks kind of ugly but to define a shape we just have to use webkit-wrap-shape and give it the values. Here are a couple I did.

     #irishpint1 {
          padding-left:0px;
     }
 
    .irishpint {
          -webkit-wrap-shape: polygon(157px,473px 106px,472px 93px,453px 91px,432px 87px,401px 84px,368px 78px,332px 70px,294px 61px,255px 57px,225px 55px,191px 55px,165px 57px,128px 63px,118px 165px,118px 274px,120px 279px,128px 282px,164px 282px,190px 282px,226px 274px,263px 267px,296px 257px,337px 253px,368px 250px,397px 246px,427px 244px,453px 233px,473px 173px,473px);
     }
 
 
     #weissbierflute1 {
          padding-left:250px;    
     }
 
     .weissbierflute {
          -webkit-wrap-shape:  polygon(104px,470px 82px,459px 81px,439px 89px,400px 105px,344px 102px,294px 86px,238px 72px,183px 66px,128px 62px,77px 59px,39px 58px,17px 57px,0 280px,0 279px,17px 278px,41px 276px,74px 271px,128px 265px,182px 251px,238px 234px,299px 232px,344px 248px,400px 255px,434px 252px,463px 215px,473px);
     }

So they’re some semi-complex polygons. I also used the div tags to set up padding and lay things out. One of the things I learned is that CSS regions/shapes can only be applied through classes, you can’t define the properties based on id’s. But that may change.

So with all of those glass polygons, it looks like this:

What the page looks like in a browser that supports CSS Exclusions

What the page looks like in a browser that supports CSS Exclusions

That page is up on GitHub but you won’t be able to view it in your browser so you’ll have to be looking at it with the special browser from Adobe labs.

Making it More Interesting

After this I thought it would be cool to do a bit more with the shapes. Beer has a rating scale for color called the SRM scale. Types of beer have a general range of SRM scales and since some glasses roughly correspond to specific types of beers I wanted to see about creating a background for each shape that would correspond to the SRM scale. But even more than that I wanted it to change with the glass so as the glass got narrower, the background would become more transparent just like a real beer glass. Unfortunately it didn’t work quite the way I wanted, but I learned a bit about using CSS shapes along the way. Originally I just started by giving the div a background:

     #irishpint1 {
          padding-left:0px;
          background: -webkit-gradient(linear, left top, left bottom,
                                             color-stop(.8, rgba(152,83,54,1)),
                                             color-stop(.2, rgba(152,83,54,.7)));
     }

But the CSS shapes/exclusions don’t actually change the shape of the div, they’re only worried about wrapping the text within the div. So my page just looked like this:

What the div tag looked like when trying to set the background

What the div tag looked like when trying to set the background

Luckily webkit-mask-image came to the rescue. With that, I could create a mask based on a file, in my case an SVG file, and use that to mask a block element like a div tag. So I went through and created an SVG file for every glass shape and then used those as the mask and set the background accordingly with rbga() properties in a gradient. The final version looks like this:

And here’s a clean(ish) version without the backgrounds. I kind of like this one better.

Update: If you have a browser that supports exclusions you can check out the demo here.

Final Thoughts

It’s really, really early for CSS Exclusions but there is a LOT of potential there and even the stuff that works now is a lot of fun to use. This was just an initial dive into the feature to kick the tires, and because it’s so new, there are a lot of gaps both in my knowledge and what I was able to do. One of the things I tried was using CSS3 transitions to animate the -webkit-wrap-shape property. That didn’t seem to work, it could be on the roadmap.

It’s a fun feature and it’s really fun to be able to give it a shot while it’s still in the early stages. For magazines or any kind of rich text content, exclusions are going to be a fantastic way to make stuff pop. If you want, you can check out the project on Github. I’ll probably be modifying it and improving it as the spec evolves.

Building a Mobile-Themed Slider without jQuery Mobile

I’m generally a big fan of jQuery mobile. I think it’s an ambitious project and it’s got some areas that could be improved, but I’m glad we’re contributing and think it’s going to be a huge boon for mobile web applications as they get bigger and bigger. But building PhoneGap applications with jQuery Mobile is a bit problematic partly because the goal for the project is “Delivering top-of-the-line JavaScript and a unified User Interface across the most-used smartphone web browsers…” and partly because jQuery Mobile can be tough to really customize if you want a specific look and feel. One of the things I wanted for something I’m working on is a slider that is a bit more boxy than the traditional slider used with jQuery Mobile. Some of this might have been possible with customizing the jQuery Mobile theme but I wanted to see what it would take to build my own from scratch.

This example is part of an app that’s using Backbone.js so I won’t post a working example because the Backbone.js infrastructure makes it kind of tough to strip out just the toggle button part. I’ll post the whole thing later, but wanted to show the general process.

The Look and Feel

To set it up I wrapped a div tag around a select tag with a couple of options. The div tag provided the border so it ended up being the track that the sider went along. This makes it pretty easy to customize the look and feel while still being very nicely degraded into a regular HTML select box.

                         <div id="toggle" class="toggleoff">
                         <select name="activetoggle" id="activetoggle" class="selectoff">
                              <option value="all">All</option>
                              <option value="active">Active</option>
                         </select>
                         </div>

Initially both the div and the select start with “off” classes. At this point the CSS starts to take over and create a more slider-looking button. There is a cool -webkit-appearance property that can be used on the slider to give it some instantaneous look/feel. But for the most part I rely on -webkit-border-image to customize the look and feel of the slider button. The CSS for the toggle button itself, the div tag, and the off states give us a basic looking toggle with no real toggle functionality because it behaves just like a regular HTML select box.

Toggle button off state

select {
     -webkit-appearance: push-button;
     margin-top: 0px;
     margin-bottom: 0px;
     height: 50px;
     width: 155px;
     border-style: solid;
     border-color: #cdcdcd;
     border-width: 1px;
     color: #555;
       font-size: 25px;
       overflow: hidden;
     padding-top: 2px;
       padding-bottom: 1px;
     white-space: nowrap;
     text-align: center;
 
}
 
.selectoff {
     -webkit-border-image: url( ../assets/button.up.png ) 4 4 4 4 stretch stretch;
     padding-left: 60px;
 
}
 
#toggle {
     margin-left: 5px;
     margin-right: 5px;
     margin-top: 5px;
     height: 50px;
     width: 312px;
     -webkit-border-radius: 2px;
     -webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);    
     border: 2px solid #cdcdcd;    
}
 
.toggleoff {
     padding-left: 158px;
     background-image: -webkit-linear-gradient(#ffffff, #e7e7e7);
}

I have the benefit of using absolute positioning because I’m building this for an iPhone, but the CSS is pretty straightforward. I’ve got some padding-left properties so I can control how the text looks and where the actual toggle button appears within the div tag. This is why this particular strategy works. When I move between states I’m just going to change the position of the toggle button, I’m not actually doing anything with the select object itself other than changing how it looks and where it is. Here are the “on” classes.

 
.selecton {
     -webkit-border-image: url(../assets/button.down.png) 4 4 4 4 stretch stretch;
     padding-left: 30px;
}
 
.toggleon {
     padding-left: 0px;
     background-image:-webkit-linear-gradient(#bccead, #cbdfba);
}

Just a couple of small changes to gradients and backgrounds so that when our button is on or active, it looks like this:

Toggle button on state

Functionality

Now that the CSS classes are set up I used jQuery to first add/remove the classes I wanted and finally set the value of the select box programatically. As I mentioned, this is using Backbone.js so the code may look a bit odd.

          onMouseDown:function(event){
               event.preventDefault();
               if(this.displayingAll) {
                    $("#activetoggle").removeClass("selectoff");
                    $("#activetoggle").addClass("selecton");
                    $("#toggle").removeClass("toggleoff");
                    $("#toggle").addClass("toggleon");
                    $("#activetoggle").val("active");         
               } else {
                    $("#activetoggle").removeClass("selecton");
                    $("#activetoggle").addClass("selectoff");
                    $("#toggle").removeClass("toggleon");
                    $("#toggle").addClass("toggleoff");    
                    $("#activetoggle").val("all");                             
               }

My Backbone view has a variable, displayingAll, which I set to either true or false depending on what is currently visible. It helps track which classes need to be added/removed. But the first, and probably most important thing, is that I’m capturing the event and keeping it from doing anything. I don’t want the default select behavior at all so I can trap it and make sure it doesn’t keep doing the rest of its work. That means no pop up where the user can select values. Instead I go through and swap out the on/off classes to change the look of my button. Finally I use the val() method to set the value of the select so that what the screen is showing is the actual value of the select input.

So now the slider is working but we haven’t done any animation. So right now the slider just jumps back and forth. It works but it isn’t all that pretty. Luckily CSS3 is pretty awesome and we can leverage the very powerful -webkit-transition to help us out.

Animation

Animation for this example is insanely simple. Using the -webkit-transition CSS property we can listen for changes in the DOM on a specific property and whenever that property changes we can play a specific transition. The way I have set this up is that I’m changing the padding-left property between on/off classes so that’s the one we have to listen for.

Quick sidenote: I struggled with this for a bit. At first I was using the align property of the div to move the toggle button back and forth. That had the benefit of being able to scale better for multiple pixel-widths. The button would move back and forth just fine but there wasn’t a way to animate the align property that I found, which makes sense. So to do animation I had to use a value that could be animated and padding-left ended up being a decent option.

In order to get the animation to trigger we have to add a single CSS property to the #toggle div tag:

     -webkit-transition: padding-left 250ms ease-out;

So whenever the padding-left property changes (on a Webkit browser) a quarter of a second ease-out transition will play and move the toggle button back and forth. Under the hood we’re changing the value of the select so that if we have to rely on that value it’s all in sync while still creating a very specific look-and-feel for our toggle button.

I realize this isn’t entirely helpful without a working demo and I’ll work on getting a jsFiddle or something up to show it but I’m working on some other bits of the project and want to be able to share the whole thing when it’s done. One of the main things I learned: CSS3 transitions aren’t entirely intuitive when coming from the Flash world, but they’re very powerful.