Friday, August 21, 2009

Gracefully downgradable javascript for accessibility

JavaScript contributes by a great deal to user experience on the Web and it does not have to be an obstacle for accessibility. The goal is to allow the user access all of the website's content when JS is enabled as well as when it is disabled.

Let's consider two versions of the webpage: one is interactive JavaScript enriched and the other one is just static. I think it is safe bet that both of them initially share same markup and only differences occur in styling.

If we stop to think about it, we have just one markup with two possible stylings applied to it. If we could detect within CSS which version of styling should be applied that would solve the case. Of course CSS on its own have no such ability but that is exactly where the "C" from CSS comes to aid: Cascading.

JavaScript, when enabled, can amend DOM. In particular it can add a class to body tag, say "js-enabled". Having styles for specific areas of the webpage, cascaded down through .js-enabled class allows you to differentiate between JS enabled and disabled state on the CSS level.

The simplest example would be a definition list. We want to display all the terms but not the definitions. The latter would be expanded and visible only when corresponding term was clicked, which needs some simple JavaScript functionality to work. On the other hand, when JS is not available the user should be able to see the whole list: the terms along with the definitions. We could do it using this CSS:
.js-enabled dd {display:none;}
.js-enabled dd.expanded {display: block;}

JavaScript would add the class "expanded" whenever there is a need to show the definition. Simply removing the class would hide the element again. I am not going to go into details of the implementation as it is not very interesting. What is interesting though is when to add the class "js-enabled" to the body tag.

If it was added after the document has been fully loaded (for example from within the "document.onload" event handler), the list would be rendered without the "js-enabled" class at first and both terms and definitions would be visible. Then adding the class would cause hiding all the definitions and as a result ugly jumping of content on the page. To prevent this effect we have to add "js-enabled" class as soon as the body tag is available for manipulating but before the document has been rendered:

<body>
<script type="text/javascript">
try {
document.getElementsByTagName("body")[0].className += " js-enabled";
} catch(e) {}
</script>
...

No comments:

Post a Comment