Chrome Apps v2: Native-Grade HTML5 on a Desktop Near You

I went yesterday to Google’s Chrome Apps hack day at Google Campus. A lot of what you hear about the new Chrome Apps is actually a v2 of the packaged app concept introduced in 2010, but focused on making apps more native like. I’ve followed this closely, but didn’t get hands-on until yesterday.

I’ll outline my initial thoughts here. For context, I hacked on a long-planned app to sync podcasts offline according to account settings (show me the source), and got as far as a scrapp that shows and plays latest episodes in all of the user’s starred channels.

As I’d booked Campus’s swish studio for a couple HNpod recordings, I didn’t get time for the offline components, but did discuss options with Chrome team.

Desktop For Now

We should firstly say that this is a desktop play. Of course, the elephant in the room is Chrome for Android, a fine marriage of two products from the same organisation that is releasing this, and it’s running on mobiles, tablets, and TVs. So the eternal dream of HTML5 Everywhere might one day be carried forward by this initiative. But for now, this is all about the desktop. And that’s a fine place to start…I’d think of it as Browser++ instead of Mobile Apps–.

Native-Like User Interface: Seriously Competitive

This is a major improvement over the original apps model and certainly in the direction I’d hoped for in the v1 era of Chrome apps. This is much more like the Adobe Air vision of write-once, run-many, native apps that sit in their own window. You don’t see browser Chrome and apps don’t even need to use a standard title bar…you can roll your own there too (Yes, you too can design a lickable 1990s MP3 player with custom title bar!). Adobe Air’s vision was actually very promising and certainly did well in the form of TweetDeck, Destroy Flickr, and others. But Adobe let the runtime languish, particularly the HTML5 runtime. And the Flash runtime dwindled along with Flash itself. In contrast, this is Chrome’s leading-edge HTML5 runtime. Gloves are off, native apps!

The caveat is that presently, it’s launched through Chrome and apps don’t launch from start menus, task bars, etc. The team has aspirations to fix all that and make the apps feel truly native, much like Adobe Air apps, but it’s obviously a lot of work, has standardisation implications, and remains to be seen if they will make good on that aspiration.

Native APIs

It’s not just a native UI. It’s native APIs. I mean, you can write a freaking IRC server in the browser! Someone has. Check out the servers in the app samples.

This is great and one of the main things missing from web apps right now. That said, it does lead to another challenge which Chrome team and devrel needs to solve: Too Much Choice!

In my case, I had to ask the question: Where am I syncing these podcast files to? Google Drive space? FileSystem API space? Or raw filesystem, given that Chrome apps can actually save files on the regular hard drive! FWIW my answer, in my specific case, FileSystem API, because it’s perhaps the most likely to be auto-sync’d in the future and doesn’t have the extra barrier of Google Drive. But the decision tree is far from clear. Just as HTML5 gave us purpose-built APIs for the hacks of Ajax era, Chrome apps are ushering in a new era where there will be a third way to do everything: Pure native. And it’s not always clear which way is the right way.

Distribution Model: Potentially Confusing, Potentially Solveable

Distribution is presently planned to happen through the Web Store, but may also change in the future. I think this may be a point of confusion for users, given there’s really no obvious tie to Chrome. Why install a standalone app from inside your browser? I presume the App Store itself might gain a more native look-and-feel and hopefully the Chrome team can provide a path that is intuitive for users, while maintaining the security benefits this approach affords.

Build Process

You don’t need a build process. You can just manually hack the manifest and build a single page app. But this is from the team that made Yeoman, and Yeoman’s Addy Osmani was on hand, so I tried it out. Once installed, Yeoman supports a yeoman init chromeapp command to auto-build a Chrome app project, so this will make the process simple. I did encounter a couple of basic bugs, which Addy’s aware of and will fix soon. Moreover, the fundamental issue right now is combining Yeoman targets. Right now, you can only initialise with a chromeapp or an Angular app or whatever…but not all of them. Addy well understands this problem and the next version of Yeoman will allow you to initialise with several targets simultaneously. So you could initialise a Chrome App that is powered by all of Angular, Bootstrap, and Testacular, for example.

Debug Process: Most Improved

Chrome app development is much easier than it was a couple years ago, thanks to some small but powerful additions. Instead of hacking URLs to find the background page location, there’s now a direct link. Instead of disabling and enabling the extension, there’s now a reload button. And so on. It’s still in need of more basic UX – put a developer in the UX lab and watch them debugging for an hour – but much better than it used to be.

Content Security Policy

This isn’t specifically about Chrome Apps, but is closely related from an end-developer’s perspective. With the new CSP setup, apps are much more restricted in terms of dynamic constructs like eval usage. The net effect is that a number of libraries don’t work in Chrome apps, e.g. libraries like jQuery Templating and Underscore templating. I found lodash’s default build doesn’t work either. My main feedback here to Chrome team would be to work with those API developers to make CSP-friendly implementations, and to guide developers on which libraries are working right now.

Window-Background Page Interaction Model: Still Confusing

The background page is the same background page concept used in Chrome extensions. It’s an invisible HTML page for your app that’s always present when the browser is on. It’s the thing that does basic polling and crunching behind the scenes.

As with Chrome apps of yore, there is still a fundamental Something’s Not Quite Right tension with background pages. It’s a rather complex interaction model for just basic communication between the background page and the UI windows, and never a true sense of which component, if any, is in charge. Again, it feels like some good old fashioned UX style research would solve this. What are devs trying to do? There really needs to be a better library/API and documented patterns to guide developers on the basic communication model between background windows and the rest of the app. (Not just UI windows, but also things like context menus and content scripts, when we’re talking about extensions.) I cobbled together a little Pub-Sub type approach which feels like the right way to do it, but it shouldn’t be anything an app developer needs to even think about.

Standardisation or No?

I’ve said this before, but fragmentation is a huge threat to the web right now, because the miserable alternative seems to be trailing years behind native apps while debating on standards. In six months, we will have a perfect litmus test, because Firefox OS will by then be in production and using similar native-like APIs to Chrome. The question is, will they be the same APIs or not? I haven’t seen a lot of evidence these really deep-impact APIs, like background processing and notifications, are being standardised, but I’m only a casual observer. What I can say is that if they’re not being standardised effectively, then efforts like Chrome apps and Firefox OS won’t make much of a dent in the onslaught of native platforms. Best I could hope for in that case, as a pragmatic developer who is ultimately motivated by the needs of end-users, is a tighter integration between Chrome and Android.

Conclusion

So, yesterday’s workshop left open a lot of questions about project direction, but also a lot of hope for the HTML5 and Chrome platforms. All that depends on how well developer feedback is taken on board, and devrel is certainly doing its part to make that happen on the basis of what we saw yesterday.

Dropdown Menu: Layout Trick for Touch Devices

I’m making a dropdown menu to explore Player FM channels, and the expandable items are quite big. So here’s a little trick I used.

On desktop, it looks like this:

A big expanding area like this could be annoying, as it’s easy to accidentally hover over a region. The important thing is it’s easy to collapse it again just by mousing up a bit, since the top of the sub-menu is aligned with the item you’ve just hovered over.

On touch devices, however, space is more limited, so we want to show more. Conversely, we don’t have the same concern as we do with a mouse, because you can’t “accidentally” touch a menu item and you can easily touch anywhere on the device to release it. So on touch devices, we vertically align the top of the submenu with the top of the main menu to show as much as possible:

How do we achieve this difference? We can use Modernizr to easily add a “touch” or “no-touch” to the root HTML element. From there, we use relative positioning, but vary the container element depending on whether it’s touch or not. SASS makes this easy:

[css] .menu .touch & position: relative &:hover .menu-item .no-touch & position: relative .submenu position: absolute top: 0 left: 100% [/css]

There are also some interesting effects of touch devices’ handling of hover states, and how this affects a CSS dropdown menu. But that’s another post.

New Look, New Host

This blog is now hosted on WPEngine. I was having trouble managing it on the Linode VPS for some time now. It seemed to cause DB issues for some reason, which would in turn lock up my other sites (WebWait, AjaxPatterns etc). So I had to isolate it on a separate Linode, and decided if I’m doing that, I may as well just go for a dedicated WordPress host. So here we are at WPEngine. And took the opportunity to cut the clutter and go for a minimalist theme. So thanks Sayanee for this here IceCap theme. Update: Or not. Having some scrolling issues, oddly enough, so reverting back to the old theme for now. Update again: Fixed. It was a conflict with the MailChimp Social plugin. Luckily, Social has an option to disable its own comment view, so I can keep both plugins active.

Feedburner URLs

I explained in the previous post that we need to canonicalise Feedburner URLs. Since about a quarter of the feeds are Feedburner, this is worth special-casing when it comes to parsing rules. Lots of different Feedburner URLs end up floating around for what it actually the same feed. This is partly because feedburner doesn’t redirect funny variants. That actually makes sense, since a lot of RSS clients apparently aren’t smart enough to handle redirects, believe it or not. Though it wouldn’t be altogether insane if they sent in a header the canonical URL. But anyway. It just serves them as happy 200 responses. So the variants end up floating around. So I need to canonicalise the variants to be the same URL. Here’s what I’ve learned.

Update: Show me the code

Full Path Matters.

The canonical URL is http://feeds.feedburner.com/[/name2]. /name2 is optional and rarely use, so most feedburner URLs are http://feeds.feedburner.com/.

For example, a typical name is http://feeds.feedburner.com/TheNerdpocalypse

Sometimes the path is longer, and you can’t ignore that full path (ie., /name2). For example, http://feeds.feedburner.com/linuxbasix/mp3 is a podcast feed, http://feeds.feedburner.com/linuxbasix is not. path. http://feeds.feedburner.com/lifestyle-business-podcast doesn’t exist, but http://feeds.feedburner.com/lifestylelife/LwyMis hours of listening pleasure.

Dulphanumeric

Looking at a big sample, it seems that you’re allowed: alphabet, numbers, dash, and underscore. That’s an 38 significant characters, given that …

Case doesn’t matter

http://feeds.feedburner.com/TheNerdpocalypse and http://feeds.feedburner.com/TheNerdPocalypSe and http://feeds.feedburner.com/thenerdpocalypse are all the same thing. For this reason, I will downcase everything to canonicalise the URL, and consider a second “pretty_url” column if we want to display the feed nicely and in line with the publisher’s proclivities.

Domain doesn’t matter

Sometimes I see http://feeds2.feedburner.com domain. I don’t know why this leaks out past Feedburner’s farm (or at least, why we don’t see hundreds of other domains like that if it does leak out), but it doesn’t matter. http://feeds2.feedburner.com/TheNerdpocalypse is the same as http://feeds.feedburner.com/TheNerdpocalypse. So whenever I see feeds2, it becomes feeds.

Slashes don’t matter

http://feeds.feedburner.com/TheNerdpocalypse/ is the same as http://feeds.feedburner.com/TheNerdpocalypse.

Suffixes don’t matter

I also see the dapper .xml or .rss variant, e.g. http://feeds.feedburner.com/TheNerdpocalypse.xml. REST envy perhaps…but the suffix does nothing useful. Ignore.

CGI doesn’t matter

?format=xml smells like even more REST envy, but afaict it doesn’t do anything either. Honeybadger don’t care.

Bonus factoid: feedproxy will redirect

A URL like http://feedproxy.google.com/TheNerdpocalypse will redirect to http://feeds.feedburner.com/TheNerdpocalypse. And this keeps the full path intact, i.e if there’s an xml on the end, it will stay on the end after the redirect.

Summary

I’ll use a URL parsing library for this. Lowercase the URL, extract the path without CGI parameters, strip the trailing slash. That will about do it.

Canonical Feeds

I’m currently building some features to help manage series “aliases” on Player FM. The idea is to canonicalise podcasts, so there’s only one true “TWIT” record in the system, for example. This is important for efficiency – it means the server’s not parsing 12 different variants of the same feed. Moreover, it’s important for user experience. It means we recognise when two users are subscribed to the same feed, so we can show them recommendations, they can share with each other, etc.

So we need aliases.

By aliases, I mean two things. Firstly, something like Wikipedia’s redirects, e.g. a feed changes title from “foo” to “bar”, now /series/foo will redirect to /series/bar. That’s basically a slug alias. Secondly, there are “feed aliases”. This is where a publisher asks me to update the show’s URL, perhaps because they’ve moved host. It may also be where a user or myself notices that a feed has changed, e.g. various people have recently been moving away from Feedburner, including 5×5 network, so I noticed their feeds are now marked “obsolete”. So we’d like to alias the old feed to the new one, so anyone in the future who imports their XML containing the old feed will automatically be subscribed to the new one.

The aliases above are all database-driven. e.g. user subscribes to feed1.xml, we look it up in the aliases table and find it’s aliased to feed2.xml, and boom…they’re subscribed to feed2.xml. But a different kind of feed alias is an “automatic” one. By which I mean no DB…just some basic parsing rules. User subscribes to feedburner.com/AbC, we transform it to feedburner.com/abc, and boom they’re subscribed to the same “abc” feed everyone else is subscribed to.

In the next post, I’ll explain how Feedburner URLs work, since that’s a big part of those automatic translations.

Do Not Reply

Says Ryan Hoover:

How many emails did you immediately delete without opening this morning? How many of those were from [email protected]? We’re drowning in unwanted, rote email yet companies miss the opportunity to escape the trash and create a connection with their users by communicate more personally.

Absolutely – don’t be an idiot by sending mails out with noreply@.

As Ryan, and also Paul, says, you’re missing out on a huge opportunity for engagement and you’re forcing your call centre to do the work.

Even worse, you’re pissing off customers no end. I’ve had this problem recently with a UK retailer (MyProtein). Being used to Amazon’s top-notch service, it’s already a bummer when they send me the wrong order, changing an option I filled out without ever informing me, but when I have no way to reply by email, and I’m forced onto their BS “ticket” system, that sets up an antagonistic “man-versus machine” relationship. Fill out a ticket? Seriously? What does a ticket mean to anyone outside the IT industry? It’s what gets you into a football stadium, not the antidote to using email, the standard communication channel for anyone but companies who’ve messed up a customer’s order.

Please. Don’t make me jump through hoops after you screwed up.

Any random e-commerce site at this point is already two steps behind Amazon to begin with. Send your mails out with no-reply and watch your customer service plummet.

Alpha channel

I’m not much of a visual designer, but here’s a subtle little use for alpha channel I found while build a related episode feature. (You may have to squint a bit here or alternatively zoom in.)

In the before pic, we have dark text on a dark-and-light texture:

The text blends into the background too much, so we can sharpen it up with a subtle background (#eee):

Better, but observing closely shows the discontinuity. So instead of full light-gray, let’s blend it into the background. Here I used a 0.5 alpha channel (rgba(240,240,240,0.5)) and to make the transition even less jarring, a 5 pixel border radius too. (I suppose I could have added a box shadow for max combo.) I think it’s considerably sharper now, but without any noticeable background.

Ten Moments that Changed the Web

Google kindly invited me to give the keynote at the inaugural London Devfest today, so I chose to cover something I’ve been reflecting on lately as HTML5, the third phase of the web, enters middle age.

The talk is titled “Ten Moments that Changed the Web” and you’ll find the slides as well as the presentation audio linked from the first slide. (Audio quality is rough as my recording was a bit impromptu and took the audio from a Flipcam.)

Thanks to Google for inviting me and thanks to Hakul for the ever-genius RevealJS slide framework.

Amazon’s Pure CSS Solution to Avoid Cutting Off Text

Amazon is using a nice CSS trick to truncate a text block without showing half-lines (like someone cut the document horizontally). The problem is that CSS “overflow: hidden;” is a crude creature that will brutally cut lines off halfway through like a 1970s dot-matrix printer. There’s no “overflow hidden, but jeez be gentle about it okay” property. So this is a workaround, but it does impose a change on the UI…the fading text on the bottom.

Using Devtools for the image below, I’ve enhanced the mask with outline and gradient colour, and also filled the block with text to build a continuous paragraph on the bottom.

There’s a semi-transparent gradient mask in front of the content. The mask is mostly clear, but has a white band on the bottom 15%. This band is turquoise for illustration purposes here. So this bottom band covers up text on the next line without occupying too much whitespace. You’ll notice the band starts where the bottom line ends. So the bottom line is already fading, and then BOOM! It’s all white below that.

The mask is 50 pixels, so there will be about 45 pixels (85% of 50px) transition from full text to fully-transparent text, followed by about 5 pixels of white.

A side note is the layout technique for the mask. Probably basic for most CSS designers, but not how I would have done it. It’s simply using standard flow, but with position: relative to shift the mask up 50px, and a 50px negative margin to ensure the mask doesn’t actually affect the flow. (I would have done it by making the whole thing position relative, and absolute elements inside it. This technique is much simpler.)

I found this technique via StackOverflow a little while ago, as mentioned here earlier, so I was chuffed to spot it in the wild, and on Amazon no less.

Update: Syd Lawrence points out that it’s worth using pointer-events: none on the mask. This is the CSS property that makes the front layer porous, allowing mouse clicks to cheekily slip through to the element behind it.

will_paginate for mobiles

I’ve been using ElasticSearch + Tire to (finally!) build Player FM search and they’ve worked well.

One little trick I used just now is a responsive pagination. I’m using will_paginate and bootstrap_will_paginate gems for this.

Normally, you get this clutter on mobile:

messed up!

Fortunately, will_paginate marks classes semantically, so you can do this instead:

responsive joy

using a SASS media query:

[css] .pagination @media (max-width: 480px) li
display: none &.active,&.prev,&.next display: inline [/css]

I think there are some other ways to do it via server-side mobile detection, but this was a simple and reliable trick.