Message
back to the journal

Unobtrusify your Javascript

January 5th, 2009

Unobtrusive Javascript

Recently Jon Lister, a colleague of mine at Osmosoft showed me a website made by his friend Joshua Bradley. The site, used some of the Javscript code from TiddlyWiki’s animation engine to create some nice visual effects. I loved the design, but could see some room for improvement in the implementation. I’m a big advocate of Unobtrusive Javascript and Progressive Enhancement and so I set about producing a quick demo of how a similar result could be achieved in the most Web-kind and accessible way available using jQuery for the behaviors.

The result has been published as Unobtrusify.com.

The aim.

  • Create a similar effect to that on Josh’s site, but make sure that the page is readable without Javascript.
  • Use images to make the headings look snazzy, but make sure that they are not required in order for the content to make sense.
  • Use only unobtrusive Javascript and keep the HTML as clean as possible.
  • Reduce the number of http requests required to as few as possible in order to improve performance.

The approach.

First of all, I wrote the text for the page. I chose a simple statement and tried to structure it such that it would make sense regardless of which sections were expanded.

Then I used the simplest HTML markup I could to logically represent the content with its various headings. This is how the page would look to text-only browsers search engines, web-crawlers and screen-readers.

I then used a well-known CSS technique to replace the text in the headings with images. This would ensure that the text would remain for non-human consumers of the site, while the images would be presented to those able to appreciate them. The technique is simple. You prevent the browser from scrolling the content of your element with overflow:hidden and then scoot the text out of the way with text-indent. Now that the way is clear, you can display an image with background-image. Be sure to specify the dimensions of your desired image as the background-image property will not resize your element to the correct size automatically. The CSS would look something like this:

#myHeading {
	text-indent: -9999px;
	overflow: hidden;
	background-image: url(myImage.gif);
	width: 380px;
	height: 123px;
}

My content had 6 headings to render in this way. I also wanted to have a mouseover effect to give some affordance for the click-ability of the headings so this would require another 6 images. Rather than having 12 images to download (which would require 12 separate HTTP requests), I combined all of these images into a single image. This would have a number of effects. Firstly, combining the 12 images into one meant that the total download would be a bit smaller due to the way that the file was compressed. (A tiny saving, but every little helps.) Secondly, there is an overhead with making HTTP requests so when it comes to performance, the fewer the better. This method cuts out 11 HTTP requests. Score! Thirdly, as the browser uses the same image for the original heading images and their associated mouseover images, there is no need to preload the alternate images to avoid that nasty pause when mousing over. The image is already downloaded and ready to display. A nice bonus.

In order to use this ‘image sprite’ for each and every heading, I just needed to specify the background-position for each one. Some attributes would be common to each one so I could save some code like this:

h1 {
	text-indent: -9999px;
	overflow: hidden;
	background-image: url(images/unobtrusive_sprite.gif);
	width: 380px;
}
 
h1#uj {
	background-position: 0 0;
	height: 123px;
}
 
h1#cmh {
	background-position: 0 -123px;
	height: 150px;
}
...

At this point our page looks like this. This is exactly how we want things to appear for those without Javascript. There is no ability to toggle the display of the various sections, the content is shown in full, and there is no mouseover behavior on the headings to suggest that they can be clicked (since they cannot). This is the essence of Progressive Enhancement. We have a perfectly serviceable web page (albeit a simple one) which we can now enhance for those with Javascript enabled.

Using jQuery to easily and unobtrusively add behavior to elements on the page, we can now hide all of the expanded sections. We do this with a simple jQuery statement like this:

$('#wrapper > div').hide();

This hides all of the div elements which are a direct descendent of the element with an ID of wrapper. (my chosen HTML structure).

Headings are not by default clickable so we can add some behavior to suggest that the clicking a heading will have a effect by changing the cursor for them like this:

$('#wrapper h1').addClass('clickable');

A CSS class of ‘clickable’ specifies the cursor with cursor: pointer;

We also use jQuery to show the hover image by just repositioning the background image when we hover with the mouse and also to show the hidden div element when we click a heading. Remember, none of this will happen unless Javascript is available.

Unobtrusify.com

I also use an additional trick to prevent a flash of unstyled content or FOUC (gratifyingly pronounced ‘FOOOOOOK’ by John Hicks) while the Javascript is being downloaded. This trick is very well explained by Karl Swedberg on the excellent learningjquery.com site.

For a better picture of exactly what is going on, why not swing by Unobtrusify.com and exercise your right as a citizen of the Web to view the source. Hitting View Source is so often the best way to learn how things are done. Go on! Go and get your hands dirty!

17 Responses to “Unobtrusify your Javascript”

  1. Jeremy Keith,

    That’s bloody marvellous, that is!

  2. Aaron Malys,

    Pretty Damn Great Point. Give me more!

  3. Jonathan Lister,

    Awesome work Phil!

    I found the CSS sprite trick a bit voodoo to begin with, but you’ve explained it well. Also, this article helps: http://www.alistapart.com/articles/sprites/

    Will poke Josh to get his site updated!

    J.

  4. Jonathan Lister,

    Hello again Phil!

    You might be pleased to know that Josh’s portfolio site is now using most of the techniques you described above, and we have another convert to jQuery fandom!

    http://www.joshuabradley.co.uk

    As a bonus, Josh has used jQuery to create a novel way of viewing a Wordpress blog - check it out:

    http://joshuabradley.co.uk/blog

    Josh has been blogging about his experiences doing all this here: http://joshuabradley.co.uk/blog/?p=122

    :)

    J.

  5. PhilHawksworth,

    Jon,

    That’s great. I’m pleased that some of the techniques from http://Unobtrusify.com have surfaced on Josh’s blog. It looks beautiful with and without javascript. Score!

    For extra credit, Josh might think about using the same technique on his home page. You can’t get to the hidden content on there with out javascript…. yet.

  6. Blog like it’s 1864! With JQuery. | Joshua Bradley: Blog,

    […] around, he found a way of achieving the same effect with the (much lighter) jQuery library, wrote a blog post about it, and even published a new site, Unobtrusify.com, dedicated to his […]

  7. Bernat Lleonart,

    The content is not accessible if images don’t load but CSS is on. I think that a better image replacement technique should be used. Moreover, I think your markup could be improved: I don’t like all those h1 (most of them don’t make sense out of context). Perhaps the whole sentence should be an h1, and spans could be used to mark up the different bits you want to style. What do you think?

  8. Cole,

    Hi Phil

    Loving the Unobtrusify site. One suggestion with my accessibility hat on.

    The Javascript should really not be mouse dependent - kind of ruins the experience for those (less fortunate) using other devices. Could do worse than use jQuery to apply a hyperlink to the H1 with wrapInner(), then using the click() function (applied to the hyperlink, remembering to ‘return false;’ within your function) which will then respond to both keyboard and mouse.

    Hope suggestion received as intended - good stuff!

    Cole

  9. Unobtrusify | WCZone Web Design! | Akron Ohio Website Design - Akron Web Development, Cleveland Web Design, Business Website,Web Programming, Akron, Summit County - Services Cuyahoga Falls Website Design Web Development, Business Website,Web Programming, ,

    […] can read all about how it was made or you can simply go and play around with it …go ahead; click on […]

  10. Steve Clay,

    I was just about to e-mail you with 2 suggestions and I see Bernat Lleonart made both. I suggest Gilder/Levin for the image replacement. Thankfully we no longer need the hacks this technique used to require, the markup/css on mezzoblue will do fine.

  11. Objetividad 2.0 | Uninstallme,

    […] Jeremy Keith, del que yo aprendí cuándo el evento onclick es dependiente de dispositivo, daba la enorabuena al autor de dicha web en los comentarios de su blog. Por suerte, otros comentarios, hacían referencia a los errores y problemas de accesibilidad que […]

  12. Cole,

    Hi Phil Posted a theoretical solution to the accessibility issue over on my blog at http://cole007.net/blog/51/unobtrusify-your-javascript Untested but should solve the problems with those using screen readers but with javascript enabled.

    Cole

  13. Sean McArthur,

    One thing I found weird, was using Javascript for the hover effect. My insides tell me you should use CSS for all the style changes.

    And you can make sure it still only happens when Javascript is enabled. Use something like: .clickable:hover { background-position:-123px 0; }

    This way, a change in the image, or “style” remains a CSS issue, and you don’t need to touch the Javascript (by changing position values.

  14. PhilHawksworth,

    Cole,

    You are quite right, and I’ll formulate a proper response on in the comments of your blog, but there are some issues with your proposed solution. I’ll try and satisfy the sensible requirement to allow keyboard navigation and post a follow up soon.

    Thanks for such a thoughtful write up!

    Phil

  15. PhilHawksworth,

    Sean,

    What an excellent suggestion! I feel an update and follow up coming on!

    Thanks, Phil

  16. Hawksworx » Blog Archive » Moving on from Osmosoft,

    […] into the browser and how. A chance to influence the nature of the browser experience by pushing for unobtrusive technologies and best practices on a range of sites which is due to increase in both reach and […]

  17. What does your website look like to me? – Is This Future Shock?,

    […] One of Paul Downey’s erstwhile colleagues, Phil Hawksworth, (@philhawksworth), is a passionate advocate of Unobtrusive Javascript and Progressive Enhancement – and made an explanatory site about this. You can see the site at unobtrusify.com, and read how unobtrusify works. […]

Post a comment





Submit your comment

WordPressRSSXHTMLCSS