Case's blog

Using HTML5 for Greater Awesomeness with Single Page Applications

Over the last few years there's been a growing amount of tension between HTML websites that use AJAX and Single Page Applications built using massive construct Javascript libraries such as Sencha.

On one side are the progressively enhanced websites where Javascript is used to enhance straight HTML websites. Folks on this side usually argue that for accessibility, customizability, indexability, or serving customers with Javascript turned off, progressive enhancement websites are the only actual option. This is helped along by the fact that Section 508 essentially said that websites using Javascript to provide content were unacceptable, largely since the tools to access those websites such as JAWS just didn't work at all for those scenarios.

On the other side of of the debate, people are already building applications on the web using Javascript, often wholesale ignoring concerns such as accessibility. These applications often feel like "native" applications, have complex controls, and can allow the user to do some pretty incredible things in intuitive ways. Single page applications can save server admins managing performance a lot of heartache by only sending and receiving requests for the actual data that needs to be displayed. Often, the Single Page Application will download all or most of the application logic when you first visit the site.

I'm not here to say which is right or which is wrong. I think the progressive enhancement folks have made a very good case, and if your top concerns are accessibility or search engine indexability, you will have a rocky road ahead with a single page application. Meanwhile, single page applications exist, and HTML5 is starting to provide mechanisms to make these application sites more accessible, and browsers are beginning to implement them. Gmail has been a single-page application for years, and they completely changed the email landscape with their application-in-browser style. This style of website-application-crossover is also being used in Google Reader, Facebook, and Twitter, with varying levels of success and persistence.

Developers have embraced REST as a mechanism for getting content, while having a bit of a blind eye to the fact that REST is often used to create the single page applications that directly contradict their recommendations for progressive enhancements. (Certainly it's not the only thing to do with JSON, but it's just so darn fast to get up and running.) Even Github, the panacea of developer geekdom, has embedded this solution into their incredible source display. How lame would it be if you had to wait for the entire website page to load every time you wanted to change folders in your source repository?

I think it's high time to stop sticking up our collective noses at something that people clearly want, and start putting effort into understanding how to resolve some of the issues of single page applications, rather than just ignoring them.

So without further ado, (because there's been a lot of ado so far)

  1. How do we deal with indexability?

    Fortunately these days the process of making a sitemap is standardized and straightforward. This (of course!) does mean that you need permalinks to access all these items in a SPA. Assuming you are using MVC, creating permalinks to your content should be straightforward. You will then probably want to have all those permalinks redirect to your index page and then deal with the permalink information as arguments to your application. Then you can use the "pushState" from HTML5 to push that permalink right back into the URL bar, so that any time your user looks at his URL bar, it represents the actual content that he is viewing. This way, if he copies the url to send it to his friend, the friend gets the content, not just your SPA home view.
    It's easy to ship this sitemap to search engines these days. Just add a reference to your sitemap in your robots.txt. Done.

  2. How do we deal with accessibility?

    These days, 98% of users using screenreaders have javascript enabled, so Javascript alone isn't the problem. It's misuse of Javascript that causes many of our problems. The other part is gaining the ability to navigate these complex UIs we're creating with JS in a screenreader. Does the user have the mindspace to deal with everything you're offering in your initial application view? Is it quick and easy to do the things she needs to do? Much of this is just now coming into shape with WAI-ARIA. There are some good texts on using it elsewhere, so I'm not going to re-iterate it here. Suffice to say, use semantic HTML5 tags for your generated content to make it easier for the screenreader to understand what you are offering, and then use WAI-ARIA to tell screenreaders how to interact with your website.

    The other part of accessibility is undoing some of the bad things we have done. You see a lot of people writing html with divs, and then adding an onClick even to the div. This doesn't look like a URL to a screenreader, and certainly doesn't act like one. The user doesn't get a "visited" pseudo-class once they've visited it and they can't interact with this link with the keyboard, since you've used onClick. Some developers instead write their javascript "links" as anchors, with a target of "#", and then add an onClick function that executes the function they want. This is only marginally better - at least the screenreader knows the user might want to interact with this item.

    From a user perspective, we have the capability now to push a URL to the URL bar. So in your OnClick function, you should also include a call that pushes the permalink URL to the URL bar for the user. Then, to get the visited class active, you should set the target of the link to that permalink URL. This way, if the user wants, they can right-click your link (which is also a JS function!) and open that item in a new tab. They can also see the visited link activate since the URL you've pushed to the history matches the URL in the href. You can see an example of this principle in action with this JSFiddle. (Thanks to Benson Kalahar for help getting this example working correctly.)

Syndicate content