Pages

Sunday, August 22, 2010

Making your menus accessible is really easy

WAI-ARIA, the Accessible Rich Internet Applications Suite, defines a way to make Web content and Web applications more accessible to people with disabilities. It especially helps with dynamic content and advanced user interface controls developed with AJAX, HTML, JavaScript, and related technologies. Currently certain functionality used in Web sites is not available to some users with disabilities, especially people who rely on screen readers and people who cannot use a mouse (e.g mobile devices users). WAI-ARIA addresses these accessibility challenges, for example, by defining new ways for functionality to be provided to assistive technology. (http://www.w3.org/WAI/intro/aria)

So, trying to make our content more accessible is a pretty important step in web development. By including roles, states and properties, ARIA helps us make our code semantically richer for the assistive technology user. ARIA enables semantic description of an element or widget behavior and enables information about groups and the elements within them. ARIA states and properties are accessible via the DOM.

A common use case is a navigation menu. Almost every site/blog out there has a tabbed navigation menu. How could we make these menus more accessible..? It just takes few attributes in our dom elements, such as "role".

The ARIA "role" attribute

The role attribute enables us to create semantic structure on elements. Two notes about roles:
  1. once set, a role should not be dynamically changed, since this will confuse the assistive technology
  2. roles take precendence over element default semantic meaning

Menu Example

Here is a simple menu we see in many sites:
<div class="topMenuWrapper"> 
 <div class="topMenuWrapperInner"> 
  <ul class="topMenuList"> 
   <li class="topMenuListItem">
     <a href="#"><span class="menuItemContent">Menu item 1</span></a>
   </li>
   <li class="topMenuListItem">
     <a href="#"><span class="menuItemContent">Menu item 2</span></a>
   </li> 
   <li class="topMenuListItem">
     <a href="#"><span class="menuItemContent">Menu item 3</span></a>
   </li> 
   <li class="topMenuListItem">
     <a href="#"><span class="menuItemContent">Menu item 4</span></a>
   </li> 
  </ul> 
 </div>
</div>
By the way, here is the CSS to make a working example, with horizontal tabs:
body {
   background-color: #F8F8F8;
}

.topMenuWrapperInner {
   margin: 5em;
   float: right;
}

.topMenuList {
   margin: 0px; 
}

.topMenuListItem {
   margin-right: 10px; 
   padding: 6px;
   display:inline;
   background-color: #ddd;
   border: 1px solid #ddd;
  /* lets add rounded corners for real browsers :P */
   -webkit-border-top-left-radius:5px;
   -webkit-border-top-right-radius:5px;
   -moz-border-radius-topleft:5px;
   -moz-border-radius-topright:5px;
}

.topMenuListItem a {
   color: #fff;
   text-decoration: none;
   font-weight: bold;   
}

.topMenuListItem:hover {
   background-color: #fff;
   border: 1px solid #ddd;
}

.topMenuListItem:hover a {
   color: #B0B0B0;
}

.menuItemContent {
   padding:10px;
} 
Now let's make our top menu accessible:
<div class="topMenuWrapper"> 
 <div role="menu" class="topMenuWrapperInner"> 
  <ul role="presentation" class="topMenuList"> 
   <li role="presentation" class="topMenuListItem">
     <a href="#" role="menuitem">
      <span class="menuItemContent">Menu item 1</span>
     </a>
    </li>
    <li role="presentation" class="topMenuListItem">
     <a href="#" role="menuitem">
      <span class="menuItemContent">Menu item 2</span>
     </a>
    </li> 
    <li role="presentation" class="topMenuListItem">
     <a href="#" role="menuitem">
      <span class="menuItemContent">Menu item 3</span>
     </a>
    </li> 
    <li role="presentation" class="topMenuListItem">
     <a href="#" role="menuitem">
      <span class="menuItemContent">Menu item 4</span>
     </a>
    </li> 
   </ul> 
 </div>
</div>
Now let's see what each attribute means:
  1. role = menu: Offers a list of choices to the user.
  2. role = presentation: An element whose role is presentational does not need to be mapped to the accessibility API.
  3. role = menuitem: A link in a menu. This is an option in a group of choices contained in a menu.
As I mentined above, its pretty easy to make our sites accessible. One nice side effect is that if you also use suggested ARIA practices, you can make your site faster to navigate with the keyboard, which benefits all users. If you are using frameworks to build your own menus, be sure to use ones that provide WAI-ARIA support, such as:
  1. YUI3: MenuNav Node Plugin
  2. Tabs - JQuery accessible RIA
If you are interested in exploring ARIA further, here are some pretty usefull resources:
  1. WAI-ARIA Best Practices, http://www.w3.org/TR/2008/WD-wai-aria-practices-20080204/
  2. WAI-ARIA Roles, http://www.w3.org/TR/wai-aria/usage#usage_intro

Sunday, August 15, 2010

JS Performance and YUI3

Javascript performance in the browser is a pretty important usability issue we have to deal with every day. The problem starts from the fact that javascript is blocking, meaning that nothing else can happen while javascript code is being executed. Browsers use a single thread to execute JS code and update the UI. Whether we include a script tag within the body of our page or in an external file, the browser will stop rendering the page and it will wait to for the script to complete. Two good techniques to improve our page's performance are:
  • grouping scripts as much as possible
  • loading JS code after the page has finished loading (aka nonblocking scripts)
A good example to look at these techniques is the YUI library. Recently I worked with YUI3 which is, I think a pretty cool library. Let's see how it works:
Grouping Scripts
Every time we include an external JS file in our HTML, an HTTP request is issued, which by itself causes an additional performance penalty. Yahoo created the combo handler to distribute the YUI library files. YUI's users can pull any number of files by using a combo-handled URL, such as: "http://yui.yahooapis.com/combo?3.1.0/build/oop/oop-min.js&3.1.0/build/dom/dom-min.js&3.1.0/build/event-custom/event-custom-min.js&3.1.0/build/event/event-base-min.js". This URL includes 4 different files and there is no need to issue 4 different HTTP requests, we can just fetch all these files with one HTTP request. Pretty cool, right?
Nonblocking Scripts
YUI uses the concept of a small initial code on the page followed by downloading additional functionality later. To use YUI3 in our page we only need to include the YUI seed file:
<script type="text/javascript" src="yui-min.js"/>
The seed file is about 10KB (6KB gzipped) and includes enough functionality to download any other YUI components in the Yahoo CDN (content delivery network). For example, if we want to use the DOM utility, we just need to specify its name within the YUI use() method. The use method will provide a callback that will be executed when the code is ready, an example piece of code is:
YUI.use("dom", function(Y) {
   var testElmt = Y.one('#test123'); //gets element by id
   // do something with the element
});
This code creates a new instance of the YUI object and then calls the use() method. The seed file has all the information about filenames and dependencies, so specifying "dom" actually builds up a combo-habdler URL with all of the correct dependency files and creates a dynamic script element to download and execute those files. When all of the code is available the callback method is called and the YUI instance is passed in as the argument, allowing to immediately start using the newly downloaded functionality. The good thing with nonblocking scripts is that the JS files are downloaded as soon as the element is added in the page, so we don't need to actually block any other process in it.





References: High Performance JavaScript, Nicholas C. Zakas (http://oreilly.com/catalog/9780596802806)

Sunday, August 8, 2010

HTML Collections are LIVE!

  var allDivs = document.getElementsByTagName('div');
  for(var i = 0; i < allDivs.length; i++) {
     document.body.appendChild(document.createElement('div'));
  }

Do you see anything wrong in this snippet of code? You would expect it to create one additional div for every div element in the DOM, so it should just double the number of div nodes in the document, right? Well, not really! This is actually an infinite loop. Why? Because the loop's exit condition is never met, as allDivs.length increases by one with every iteration.

As defined in the DOM standard, HTML collections are "assumed to be live", meaning that they are automatically updated when the underlying document is updated.

So, here is the solution: Store the collection in a local variable, cache the length outside the loop and then use a local variable inside the loop for elements that are accessed more than once. e.g

  var coll = document.getElementsByTagName('div');
  var len = coll.length;
  for (var count = 0; count < len; count++) {
     // if needed cache in here the elements, to work with
     var el = coll[count];
     // do whatever
  }
This will do the magic and solve your problem!

Let's take it one step further. What if you want to touch every element you retrieve from this collection in a way that modifies the live collection. A common example is to replace a class from a collection of elements. e.g

  var allDivs = document.getElementsByClassName('class1');
  for (var i = 0; i < allDivs.length; i++) {
     allDivs[i].className = 'class2';
  }
This doesn't work, since allDivs changes with every iteration of the loop. In this case the best solution to go with is to actually copy the collection into an array and work with the array instead. Something like this:
  function toArray(collection) {
    var result = [];
    var len = collection.length;
    for (var i = 0; i < len; i++) { result[i] = collection[i]; }
    return result; 
  }
  
  var allDivs = document.getElementsByClassName('class1');
  var ar = toArray(coll); //copies a collection into an array
  for(var i = 0; i < ar.length; i++) {
     ar[i].className = 'class2';
  }

Now let's look at another neat solution to this problem (unfortunately not supported by all browsers, i.e Internet Explorer 6 and 7). The document.querySelectorAll() method, is provided as a native DOM method. What's cool with it? You can provide a CSS selector as an argument and it will return you a non-live NodeList, an array-like object containing matching nodes, which will not represent the live structure of the document. Let me note here that in W3C's DOM specifications NodeLists are live, but in the case of querySelectorAll(), its explicitly specified that the returned Nodelist is static (not-live)! So, with this method we don't need to be as verbose as we used to be, e.g instead of calling

var elmts = document.getElementsById('menu').getElementsByTagName('a');
we can do something like:
var elmts = document.querySelectorAll('#menu a');
and of course there's no need to cache/copy variables, in order to access them.

Last but not least...use a library if possible! Avoid dealing with this problem and let the library (e.g YUI, jQuery) do its magic!




References: High Performance JavaScript, Nicholas C. Zakas (http://oreilly.com/catalog/9780596802806)

Hello World!

Hi, my name is Yiota Tsakiri. I am a software engineer. I live in the San Fransisco Bay Area.


If you wonder about my site's name, it's inspired by the Yottabyte