On web apps and their keyboard shortcuts

Yesterday, I released dabblet. One of its aspects that I took extra care of, is it’s keyboard navigation. I used many of the commonly established application shortcuts to navigate and perform actions in it. Some of these naturally collided with the native browser shortcuts and I got a few bug reports about that.
Actually, overriding the browser shortcuts was by design, and I’ll explain my point of view below.

Native apps use these shortcuts all the time. For example, I press Cmd+1,2,3 etc in Espresso to navigate through files in my project. People press F1 for help. And so on. These shortcuts are so ingrained in our (power users) minds and so useful that we thoroughly miss them when they’re not there. Every time I press Cmd+1 in an OSX app and I don’t go to the first tab, I’m distraught. However, in web apps, these shortcuts are taken by the browser. We either have to use different shortcuts or accept overriding the browser’s defaults.

Using different shortcuts seems to be considered best practice, but how useful are these shortcuts anyway? They have to be individually learned for every web app, and that’s hardly about memorizing the “keyboard shortcuts” list. Our muscles learn much more slowly than our minds. To be able to use these shortcuts as mindlessly as we use the regular application shortcuts, we need to spend a long time using the web app and those shortcuts. If we ever do get used to them that much, we’ll have trouble with the other shortcuts that most apps use, as our muscles will try to use the new ones.

Using the de facto standard keyboard shortcuts carries no such issues. They take advantage of muscle memory from day one. If we advocate that web is the new native, it means our web apps should be entitled to everything native apps are. If native editors can use Cmd+1 to go to the first tab and F1 for help, so should a web editor. When you’re running a web app, the browser environment is merely a host, like your OS. The focus is the web app. When you’re working in a web app and you press a keyboard shortcut, chances are you’re looking to interact with that app, not with the browser Chrome.

For example, I’m currently writing in WordPress’ editor. When I press Cmd+S, I expect my draft to be saved, not the browser to attempt to save the current HTML page. Would it make sense if they wanted to be polite and chose a different shortcut, like Alt+S? I would have to learn the Save shortcut all over again and I’d forever confuse the two.

Of course, it depends on how you define a web app. If we’re talking about a magazine website for example, you’re using the browser as a kind of reader. The app you’re using is still the browser, and overriding its keyboard shortcuts is bad. It’s a sometimes fine distinction, and many disagreements about this issue are basically disagreements about what constitutes a web app and how much of an application web apps are.

So, what are your thoughts? Play it safe and be polite to the host or take advantage of muscle memory?

Edit: Johnathan Snook posted these thoughts in the comments, and I thought his suggested approach is pure genius and every web UX person should read it:

On Yahoo! Mail, we have this same problem. It’s an application with many of the same affordances of a desktop application. As a result, we want to have the same usability of a desktop application—including with keyboard shortcuts. In some cases, like Cmd-P for printing, we’ll override the browser default because the browser will not have the correct output.

For something like tab selection/editing, we don’t override the defaults and instead, create alternate shortcuts for doing so.

One thing I suggest you could try is to behave somewhat like overflow areas in a web page. When you scroll with a scroll mouse or trackpad in the area, the browser will scroll that area until it reaches it’s scroll limit and then will switch to scrolling the entire page. It would be interesting to experiment with this same approach with other in-page mechanisms. For example, with tabs, I often use Cmd-Shift-[ and Cmd-Shift-] to change tabs (versus Cmd-1/2/3, etc). You could have it do so within the page until it hits its limit (first tab/last tab) and then after that, let the event fall back to the browser. For Cmd-1, have it select the first tab. If the user is already on the first tab, have it fall back to the browser.

Introducing dabblet: An interactive CSS playground

I loved JSFiddle ever since I first used it. Being able to test something almost instantly and without littering my hard drive opened new possibilities for me. I use it daily for experiments, browser bug testcases, code snippet storage, code sharing and many other things. However, there were always a few things that bugged me:

  • JSFiddle is very JS oriented, as you can tell even from the name itself
  • JSFiddle is heavily server-side so there’s always at least the lag of an HTTP request every time you make an action. It makes sense not to run JS on every keystroke (JSBin does it and it’s super annoying, even caused me to fall in an infinite loop once) but CSS and HTML could be updated without any such problems.
  • I’m a huge tabs fan, I hate spaces for indenting with a passion.
  • Every time I want to test a considerable amount of CSS3, I need to include -prefix-free as a resource and I can’t save that preference or any other (like “No library”).
Don’t get me wrong, I LOVE JSFiddle. It was a pioneer and it paved the way for all similar apps. It’s great for JavaScript experiments. But for pure CSS/HTML experiments, we can do better.
The thought of making some interactive playground for CSS experiments was lingering in my mind for quite a while, but never attempted to start it as I knew it would be a lot of fascinating work and I wouldn’t be able to focus on anything else throughout. While I was writing my 24ways article, I wanted to include lots of CSS demos and I wanted the code to be editable and in some cases on top of the result to save space. JSFiddle’s embedding didn’t do that, so I decided to make something simple, just for that article. It quickly evolved to something much bigger, and yes I was right, it was lots of fascinating work and I wasn’t able to focus on anything else throughout. I even delayed my 24ways article for the whole time I was developing it, and I’m grateful that Drew was so patient. After 3 weeks of working on it, I present dabblet.

Continue reading

Vendor prefixes have failed, what’s next?

Edit: This was originally written to be posted in www-style, the mailing list for CSS development. I thought it might be a good idea to post it here as other people might be interested too. It wasn’t. Most people commenting didn’t really get the point of the article and thought I’m suggesting we should simply drop prefixes. Others think that it’s an acceptable solution for the CSS WG if CSS depends on external libraries like my own -prefix-free or LESS and SASS. I guess it was an failure of my behalf (“Know your audience”) and thus I’m disabling comments.

Discussion about prefixes was recently stirred up again by an article by Henri Sivonen, so the CSS WG started debating for the 100th time about when features should become unprefixed.

I think we need to think out of the box and come up with new strategies to solve the issues that vendor prefixes were going to fix. Vendor prefixes have failed and we can’t solve their issues by just unprefixing properties more early.


The above might seem a bold statement, so let me try to support it by recapping the serious issues we run into with vendor prefixes:

1. Unnecessary bloat

Authors need to use prefixes even when the implementations are already interoperable. As a result, they end up pointlessly duplicating the declarations, making maintenance hard and/or introducing overhead from CSS pre- and post-processors to take care of this duplication. We need to find a way to reduce this bloat to only the cases where different declarations are actually needed.

2. Spec changes still break existing content

The biggest advantage of the current situation was supposed to be that spec changes would not break existing content, but prefixes have failed to even do this. The thing is, most authors will use something if it’s available, no questions asked.  I doubt anyone that has done any real web development would disagree with that. And in most cases, they will prefer a slightly different application of a feature than none at all, so they use prefixed properties along with unprefixed. Then, when the WG makes a backwards-incompatible change, existing content breaks.

I don’t think this can really be addressed in any way except disabling the feature by default in public builds. Any kind of prefix or notation is pointless to stop this, we’ll always run into the same issue. If we disable the feature by default, almost nobody will use it since they can’t tell visitors to change their browser settings. Do we really want that? Yes, the WG will be able to make all the changes they want, but then then who will give feedback for these changes? Certainly not authors, as they will effectively have zero experience working with the feature as most of them don’t have the time to play around with features they can’t use right now.

I think we should accept that changes will break *some* existing content, and try to standardize faster, instead of having tons of features in WD limbo. However, I still think that there should be some kind of notation to denote that a feature is experimental so that at least authors know what they’re getting themselves into by using it and for browsers to be able to experiment a bit more openly. I don’t think that vendor prefixes are the right notation for this though.

3. Web development has become a popularity contest

I’ll explain this with an example: CSS animations were first supported by WebKit. People only used the -webkit- prefix with them and they were fine with it. Then Firefox also implemented them, and most authors started adding -moz- to their use cases. Usually only to the new ones, their old ones are still WebKit only. After a while, Microsoft announced CSS animations in IE10. Some authors started adding -ms- prefixes to their new websites, some others didn’t because IE10 isn’t out yet. When IE10 is out, they still won’t add it because their current use cases will be for the most part not maintained any more. Some authors don’t even add -ms- because they dislike IE. Opera will soon implement CSS animations. Who will really go back and add -o- versions? Most people will not care, because they think Opera has too little market share to warrant the extra bloat.

So browsers appear to support less features, only because authors have to take an extra step to explicitly support them. Browsers do not display pages with their full capabilities because authors were lazy, ignorant, or forgetful. This is unfair to both browser vendors and web users. We need to find a way to (optionally?) decouple implementation and browser vendor in the experimental feature notation.


There is a real problem that vendor prefixes attempted to solve, but vendor prefixes didn’t prove out to be a good solution. I think we should start thinking outside the box and propose new ideas instead of sticking to vendor prefixes and debating their duration. I’ll list here a few of my ideas and I’m hoping others will follow suit.

1. Generic prefix (-x- or something else) and/or new @rule

A generic prefix has been proposed before, and usually the argument against it is that different vendors may have incompatible implementations. This could be addressed at a more general level, instead of having the prefix on every feature: An @-rule for addressing specific vendors. for example:

@vendor (moz,webkit,o) {
    .foo { -x-property: value; }

@vendor (ms) {
    .foo { -x-property: other-value; }

A potential downside is selector duplication, but remember: The @vendor rule would ONLY be used when implementations are actually incompatible.

Of course, there’s the potential for misuse, as authors could end up writing separate CSS for separate browsers using this new rule. However, I think we’re in a stage where most authors have realized that this is a bad idea, and if they want to do it, they can do it now anyway (for example, by using @-moz-document to target Moz and so on)

2. Supporting both prefixed and unprefixed for WD features

This delegates the decision to the author, instead of the WG and implementors. The author could choose to play it safe and use vendor prefixes or risk it in order to reduce bloat on a per-feature basis.

I guess a problem with this approach is that extra properties mean extra memory, but it’s something that many browsers already do when they start supporting a property unprefixed and don’t drop the prefixed version like they should.

Note: While this post was still in draft, I was informed that Alex Mogilevsky has suggested something very similar. Read his proposal.

3. Prefixes for versioning, not vendors

When a browser implements a property for the first time, they will use the prefix -a-. Then, when another browser implements that feature, they look at the former browser’s implementation, and if theirs is compatible, they use the same prefix. If it’s incompatible, they increment it by one, using -b- and so on.

A potential problem with this is collisions: Vendors using the same prefix not because their implementations are compatible but because they developed them almost simultaneously and didn’t know about each other’s implementation. Also, it causes trouble for the smaller vendors that might want to implement a feature first.

We need more ideas

Even if the above are not good ideas, I’m hoping that they’ll inspire others to come up with something better. I think we need more ideas about this, rather than more debates about fine-tuning the details of one bad solution.

Animatable: A CSS transitions gallery

What kind of transitions can you create with only one property? This is what my new experiment, animatable aims to explore.

It’s essentially a gallery of basic transitions. It aims to show how different animatable properties look when they transition and to broaden our horizons about which properties can be animated. Hover over the demos to see the animation in action, or click “Animate All” to see all of them (warning: might induce nausea, headache and seizures 😛 ). You can also click on it to see more details and get a permalink. Instead of clicking, you can also navigate with the arrow keys and press Esc to return to the main listing.

Fork it on Github and add your own ideas. Be sure to add your twitter username to them as a data-author attribute!

I’ve only tested in Firefox and Chrome for OSX so far. Not sure which other browsers are supported. However, since it uses CSS animations, we know for sure that it won’t work in browsers that don’t support CSS animations.

Hope you enjoy it 🙂

My experience from Fronteers, JSConf EU, Frontend and FromTheFront

This month has been very busy conference-wise. I had 4 conferences in a row, so I was flying from country to country and giving talks for 2 weeks. As I usually do after conferences, this post sums up my experiences and feedback I got from these conferences, in chronological order. Continue reading

Optimizing long lists of yes/no values with JavaScript

My newest article on Smashing Magazine’s coding section is for the geekiest among you. It’s about how you can pack long lists of boolean values into a string in the most space-efficient way. Hope you enjoy it 🙂

Easily keep gh-pages in sync with master

I always loved Github’s ability to publish pages for a project and get the strain out of your server. However, every time I tried it, I struggled to keep the gh-pages branch up to date. Until I discovered the awesome git rebase.

Usually my github workflow is like this:

git add .
git status // to see what changes are going to be commited
git commit -m 'Some descriptive commit message'
git push origin master

Now, when I use gh-pages, there are only a few more commands that I have to use after the above:

git checkout gh-pages // go to the gh-pages branch
git rebase master // bring gh-pages up to date with master
git push origin gh-pages // commit the changes
git checkout master // return to the master branch

I know this is old news to some of you (I’m a github n00b, struggling with basic stuff, so my advice is probably for other n00bs), but if I had read this a few months ago, it would’ve saved me big hassles, so I’m writing it for the others out there that are like me a few months ago.

Now if only I find an easy way to automate this… 🙂

PrefixFree: Break free from CSS prefix hell!

I wrote this script while at the airport travelling to Oslo and during the Frontend 2011 conference. I think it’s amazing, and it makes authoring CSS3 a pleasure.

Read my announcement about it on Smashing Magazine.

Hope you like it!

My experience from Frontendconf Zurich

I’m writing this blog post while eating some of the amazing Lindt chocolates I got for free 10 days ago at Frontend conference in Zurich. But it wasn’t a good experience only because of them!

Continue reading

Major update to Chainvas: modularity, a client side build script & more

A week ago, I released Chainvas. It was a spin-off script I wrote while developing my cubic-bezier tool, to make using the Canvas API a bit less painful. However, unlike similar attempts to make the Canvas API chainable, most of my code was written in a very generic manner, and was actually able to make every API chainable. However, when I released it, even though I mentioned that it can be used for other APIs and provided some examples, practically everyone that shared the link on twitter or other means (thank you .net magazine for the newsletter mention btw!) focused on what Chainvas did for Canvas.

Actually, while using Chainvas myself, I found it immensely more useful for chaining DOM methods and setting multiple element properties at once. Chainvas had a lot of potential, that most people were missing. And then it dawned on me: I should modularize the library! A generic chaining library at its core and additional modules for making the different APIs chainable. And I did it.

On the way to that, I added IE8 compatibility, and tested in many other browsers, thanks to Browserstack. I actually found that Chainvas’ core even works in IE6! I also wrote unit tests, a much more extensive documentation, added a script generated table of contents and designed a logo and a Chainvas pride banner.

Also, since it was now modular, it needed a build script. I badly wanted to make this client side, so I followed this architecture:

  • Every module is included in chainvas.js and chainvas.min.js, along with a header comment that follows a specific syntax.
  • The user selects a compression level and then, the relevant script is downloaded through XHR and split into parts according to the module headers. Then a module list is generated with checkboxes for the user to select the ones they want to include.
  • When the user checks and unchecks those checkboxes, the URL of the download link changes to a data URI that contains the script.
This approach has the disadvantage that there is no default filename, and the “Save page as…” link is deactivated in Chrome (why Chrome??). However, I like the idea so much, I don’t mind these shortcomings.
That’s about it. Enjoy and let me know about any bugs.