Home » Tutorials Advanced Tutorial

JavaScript and Accessibility. Pt. 3.

2.4/5.0 (16 votes total)
Rate:

Jonathan Fenocchi
February 17, 2006


Jonathan Fenocchi
Jonathan Fenocchi is a talented young developer coming at you from southern TX, USA. Accessibility advocate, proficient programmer, and determined designer, Jonathan spends his free time researching new technologies, developing new ideas, playing video games and listening to rock music. Jonathan runs a Slightly Remarkable blog where he focuses on web-related content, and continues to pursue his goals as an aspiring web developer."

Jonathan Fenocchi has written 20 tutorials for JavaScriptSearch.
View all tutorials by Jonathan Fenocchi...

Last week, we covered Form Validation and JavaScript Image Rollovers. This week completes the series. Topics covered today are Drop-down Navigation Selections, DHTML Menus, Proprietary Alternatives, Document.all, and innerHTML. [Ed. note.]

Drop-down Navigation Selections

Drop-down select menus have often been used to redirect readers when they select an option from the drop-down menu. Here is an example of the misuse of a select menu:

<script type="text/javascript"><!--
  function redir(sel){
    document.location = sel.options[sel.options.selectedIndex].value;
  }
//--></script>

<form action="" method="get"><fieldset>
  <label>
    <select size="1" name="selObj" onchange="redir(this)">
    <option value="index.html">Home</option>
    <option value="about.html">About</option>
    <option value="history.html">History</option>
    <option value="music.html">Music</option>
    <option value="contact.html">Contact</option>
  </select>
</label>
</fieldset></form>

There isn’t a big problem with the JavaScript – it works, doesn’t it? This is correct, however, just as the FONT tag will work in a Strict DTD even though it is not supposed to, the deprecated “document.location” property may work but that’s not it’s purpose. An official resource says that “Location is not a property of the document object; its equivalent is the document.URL property. The document.location property, which is a synonym for document.URL, is deprecated.” Instead, the “location.href” or “window.location.href” property should be used.

Most of the problems with this classical script are in the HTML. First, there is no “action” for the form to access. This means that users without JavaScript won’t be able to use the form. They can’t use it for navigation, so what good is it to them? You might think we should hide it from them altogether, but that is not correct. Although it’s a wise decision not to rely on this kind of menu for your primary navigation, suppose this was the only logical way you could have a navigation menu. We should make this form do the requested action, regardless of the presence of JavaScript.

<script type="text/javascript"><!--
  function redir(sel){
    location.href = sel.options[sel.options.selectedIndex].value;
  }
//--></script>

<form action="some-script.pl" method="get"><fieldset>
  <label>
    <select size="1" name="selObj" onchange="redir(this)">
      <option value="index.html">Home</option>
      <option value="about.html">About</option>
      <option value="history.html">History</option>
      <option value="music.html">Music</option>
      <option value="contact.html">Contact</option>
    </select>
  </label>
  <label>
    <input type="submit" value="Go!">
  </label>
</fieldset></form>

The new JavaScript uses “location.href” instead of the deprecated “document.location” property. You’ll notice that there is now an action available, which goes to “some-script.pl.” This would be a Perl script by definition. Also a submit button was added. Now, users without JavaScript can select a page name, click “Go!” and be redirected to the page they selected. That is, if and only if the “some-script.pl” script is written to interpret the request properly. Make sure you provide a server-side alternative that will work without JavaScript.

DHTML Menus

As you’ve been reading, you might be thinking that there’s no way that you can build a menu and make it accessible. You have to use NOSCRIPT tags or something else, don’t you? The NOSCRIPT tag is always an available alternative, but it is not always the best way to solve a problem. If you’re already using a menu script that requires JavaScript, it’s useful to provide a list of some kind that shows up in the NOSCRIPT tags. If you want to make a DHTML menu without JavaScript, read on.

“Wait, you mean a JavaScript-free cascading menu? You’re kidding, right?” To be frank, Leonardo da Vinci wasn’t the most popular guy around in his day either. He was an amazing, innovative person, but ridiculed for his ideas. “Man will never fly,” he was told. Although he never grasped the basics of flight, which he was most interested in, he did know it was possible. “Birds fly; they are our example,” he thought. The example that birds provide is not applicable to us as humans, but the concept is. Airplanes do not flap their wings and humans do not have hollow bones, but birds both flap their wings and have hollow bones.

In contrast, we’re going to study an example of a CSS-powered menu that is applicable and can replace any JavaScript-powered menu. It loads and runs faster, due to less browser processing. One warning in advance: The CSS-powered menu requires JavaScript for Internet Explorer, which does not understand the “hover” pseudo-class in CSS for elements other than A tags. In other words, for this to work in Internet Explorer, we must use an MSIE-only CSS property to import a small JavaScript file that will allow Internet Explorer to use our menu. This will result in invalid CSS but not invalid HTML – if you’re concerned that your CSS will be invalid, you can try a different technique. Invalid CSS is not a problem if you know why it’s invalid and the result of its invalidity. In this case, there are no reproaches to using an MSIE-only CSS property since only MSIE will be affected and the property is used positively.

Let’s begin with a preview of the menu. It works well for me and it’s very fast. Here’s the HTML for the menu:

<div id="nav">
<ul class="root">
<li class="hassub"><a href="#">Item 1</a>
  <ul class="sub1">
      <li class="hassub"><a href="#">Item 1.1</a>
         <ul class="sub2">
             <li><a href="#">Item 1.1.1</a></li>
             <li class="hassub"><a href="#">Item 1.1.2</a>
                 <ul class="sub3">
                     <li><a href="#">Item 1.1.2.1</a></li>
                     <li><a href="#">Item 1.1.2.2</a></li>
                     <li><a href="#">Item 1.1.2.3</a></li>
                 </ul></li>
             <li><a href="#">Item 1.1.3</a></li>
          </ul></li>
             <li><a href="#">Item 1.2</a></li>
             <li><a href="#">Item 1.3</a></li>
             <li><a href="#">Item 1.4</a></li>
             <li><a href="#">Item 1.5</a></li>
             <li><a href="#">Item 1.6</a></li>
      </ul></li>
<li class="hassub"><a href="#">Item 2</a>
      <ul class="sub1">
             <li><a href="#">Item 2.1</a></li>
             <li><a href="#">Item 2.2</a></li>
             <li><a href="#">Item 2.3</a></li>
             <li><a href="#">Item 2.4</a></li>
             <li><a href="#">Item 2.5</a></li>
             <li><a href="#">Item 2.6</a></li>
      </ul></li>
<li class="hassub"><a href="#">Item 3</a>
      <ul class="sub1">
             <li><a href="#">Item 3.1</a></li>
             <li><a href="#">Item 3.2</a></li>
             <li><a href="#">Item 3.3</a></li>
             <li><a href="#">Item 3.4</a></li>
             <li><a href="#">Item 3.5</a></li>
             <li><a href="#">Item 3.6</a></li>
      </ul></li>
<li class="hassub"><a href="#">Item 4</a>
      <ul class="sub1">
             <li><a href="#">Item 4.1</a></li>
             <li><a href="#">Item 4.2</a></li>
             <li><a href="#">Item 4.3</a></li>
             <li><a href="#">Item 4.4</a></li>
             <li><a href="#">Item 4.5</a></li>
             <li><a href="#">Item 4.6</a></li>
      </ul></li>
</ul>
</div>

As you can see, it’s just a list. If you disable CSS, you’ll see an unordered list with unordered sub-lists. That means that you can just use simple HTML to create an unordered list of your site’s menu, and then format it with CSS. Take note of the classes applied to the menu items that have sub-menus and the classes applied to those sub-menus. Those are necessary for our menu. Let’s look at the CSS, shall we?

#nav li
    { behavior: url('CSSNavIEHover.htc');
    }

body
    { font-family: Arial, sans-serif;
    }

a
    { color: #113;
        text-decoration: none;
    }

#nav a
    { width: 100%;
        display: block;
    }

#nav ul
    { display: block;
        margin: 1em 1ex;
        padding: 0px 1ex;
        width: 7em;
    }

#nav li
    { display: block;
        list-style: none;
        padding: 0.1em 1ex;
    }

#nav li:hover, #nav li.hover
    { background: #eef;
    }

#nav ul.sub1, #nav ul.sub2, #nav ul.sub3
    { position: absolute;
        margin: -0.75em 0px 0px 6em;
        border: solid #113 1px;
        padding: 1em 0.5em;
        background: #aaf;
        width: 7em;
        display: none;
    }

#nav ul.root li:hover ul.sub1, #nav ul.root li.hassubhover ul.sub1
    { display: block;
    }

#nav ul.sub1 li:hover ul.sub2, #nav ul.sub1 li.hassubhover ul.sub2
    { display: block;
    }

#nav ul.sub2 li:hover ul.sub3, #nav ul.sub2 li.hassubhover ul.sub3
    { display: block;
    }


#nav li.hassub
    { background: url('plus.gif') no-repeat 90% 50% ;
    }

#nav li.hassub:hover, #nav li.hassubhover
    { background: url('plush.gif') no-repeat 90% 50% ;
    }

You’ll notice the “behavior” property. Gasp! That isn’t a valid CSS property! It isn’t, but Internet Explorer thinks it is. Here’s what’s in that file, and why we’re using it. Create a new text file, paste in that code, and save it with the “.HTC” extension so that we can use a hover class for Internet Explorer.

All of the links (A elements) in the “nav” DIV are set at block-level and 100% width. This means that they will be 100% of the width of the element they are in; they will also start a new line and any element will also have a new line after it. See: definition of block-level. All unordered lists in the “nav” DIV are set to display as block and given a width of 7em, and all list items in those lists have their bullets removed and get a little extra padding.

Here comes the fun part. When you hover over any list item, it gets a background color. Since the “hover” pseudo-class isn’t supported in Internet Explorer, we add the “.hover” class. The “.HTC” file we included earlier will indicate that whenever we hover over an element, its class is “hover.”

Note: multiple classes are supported; the hover class is added to any class or classes that already exist, and removed when the mouse is taken off of the element.

Next, all of the sub menus are hidden - unordered lists with the class “sub1,” “sub2,” or “sub3.” This is because these are the menus that should appear when we put our mouse over the parent list item of each (list items in the “root” list). All of the list items in the root list (not any of the sub lists) display the sub lists below them by setting their “display” property to “block.” You might recall that originally, we defaulted all of the sub lists to “display none.” This is done individually for all three sub-lists. Notice that the first rule displays the “sub1” menu when you hover over a list item in the “root” menu; in the second rule, when you hover over a list item in the “sub1” menu, it displays the “sub2” menu; and likewise, the third rule displays the “sub3” menu when you hover over a list item in the “sub2” menu. In the event that there is no sub menu available for an item, nothing will appear since nothing exists.

The last two rules are for adding those arrows to elements that have sub menu items. We added the class “hassub” to the menu items that had one or more menus. We add a background to this class to show our arrow, and we change it by using the “hover” pseudo-class (or the “hover” class for Internet Explorer). As mentioned earlier, this technique is not the only one; there are others out there, but this one is my preference.

Proprietary Alternatives

As I said earlier, there are some proprietary codes that work – or should work – only in Internet Explorer. It’s wise to avoid using these properties, since they don’t conform to the W3C recommendation. Instead, a better idea is to use the codes specified in the DOM.

Document.all

The “document.all” object is an array collection of all of the elements with names or ID’s on the web page. So if you have a DIV with the ID “myDiv,” you could refer to the “myDiv” object with document.all[“myDiv”]. This is IE-proprietary, though. Instead, a better option is the getElementById() method, which is used in a similar way: document.getElementById(“myDiv”) refers to the DIV object with the ID “myDiv.” When there are multiple elements with the same ID (although this should never be the case), this method will return the first one; document.all returns a collective array of those elements with the same ID, which is more likely to result in undesired results.

innerHTML

A common property used to change the HTML within an element is the innerHTML property. You use the innerHTML property by referring to an element and then setting its value. Using our above example with the getElementById method, you would set this property with document.getElementById(“myDiv”).innerHTML = “<p>Hello, World!</p>”;. An alternative to this is to update the text within an element: document.getElementById(“myDiv”).firstChild.data = “Hello, World!”;. The “data” property will not process HTML code, so if you want to add an HTML element, you have to create it. In fact, it is almost exactly the same as the “innerText” property, which also shouldn’t be used (since it is also proprietary and only works in Internet Explorer). Here’s a quick example:

<script type="text/javascript"><!--
   onload = function(){
      var p = document.createElement("P");
          p.setAttribute("style","font-family:arial");
          p.setAttribute("id","myPara");
          p.appendChild(document.createTextNode("Hi, this is what I have to say!"));
      document.body.appendChild(p);
      window.setTimeout("updatePara()", 5000);
   }
   function updatePara(){
      if(document.getElementById && document.getElementById("myPara")){
      document.getElementById("myPara").firstChild.data = "Hi, I changed the message five seconds later!";
   }
 }
//--></script>

Conclusion

In conclusion, here’s a recap:

    1. Keep this JavaScript self-test list handy. Only use JavaScript when it’s necessary and practical. Flashing text or flying buttons aren’t what JavaScript was made for, and they rarely, if ever, help the end-user. Don’t do it because it’s “cool.”
    2. As a rule of thumb (when possible), store your JavaScript and/or CSS documents in a separate file so that they can be cached.
    3. Use CSS to design your web sites. Using tables for your layouts is wrong.
    4. Always check for cross-compatibility and/or alternative functionality. Too often do I visit a web site in my wonderful, safe Mozilla Firefox and find that I am forced to use Internet Explorer to get the content I want. That is not the meaning of accessibility! For information to be accessible, it must be available to any device accessing it – not just Internet Explorer.

Thanks for reading this article. I hope it promotes the use of proper, valid JavaScript and other coding techniques. The Internet’s information should be available to anyone, regardless of race, nationality, background or disability. Let’s make the Internet a better place, for all of us.


Add commentAdd comment (Comments: 0)  

Advertisement

Partners

Related Resources

Other Resources

arrow