TJKDesign: Home Page

ez-css Putting the 'less' in table-less layouts. css-101 logo
Bookmark this article at these sites:

When an authoring tool adds bells and whistles, things can go wrong.

This article is about understanding what's involved with such gimmicks:

  • semantics,
  • separation of layers,
  • progressive enhancement,
  • keyboard navigation,
  • etc.

For the purpose of this article, I've created four test pages:

  • Page 1 contains the Spry tabbed panels widget ("out-of-the-box"),
  • Page 2 is the same as above, but includes minor fixes,
  • Page 3 "displays" the same tabbed panels, but it is built with "best practice" in mind,
  • Page 4 is a variation of page 3, it keeps everything in the flow.

Each page contains two sets of links to let you:

  1. test the page without CSS and/or JS support files.
  2. navigate from one page to another.

To demonstrate the role that the markup plays when it comes to tabbing navigation (keyboard navigation), I've placed a link within the content for the second tab.

Out-of-the-box Spry Tabbed-Panels (v1.4)

This is the markup:

<div id="TabbedPanels1" class="TabbedPanels">
	<ul class="TabbedPanelsTabGroup">
		<li class="TabbedPanelsTab" tabindex="0">Tab 1</li>
		<li class="TabbedPanelsTab" tabindex="0">Tab 2</li>
		<li class="TabbedPanelsTab" tabindex="0">Tab 3</li>
		<li class="TabbedPanelsTab" tabindex="0">Tab 4</li>
	</ul>
	<div class="TabbedPanelsContentGroup">
		<div class="TabbedPanelsContent">Content for Tab 1</div>
		<div class="TabbedPanelsContent">Content for Tab 2</div>
		<div class="TabbedPanelsContent">Content for Tab 3</div>
		<div class="TabbedPanelsContent">Content for Tab 4</div>
	</div>
</div>

We have a wrapper in which we find a list and another wrapper that includes a bunch of DIVs; and every opening tag in there has at least one attribute. It is not pretty...

This markup creates absolutely no relationship between the tabs and the content of the panels. To see for yourself visit Page 1 and use the link that turns both support files off. The way the page appears to you without CSS nor script support is the way it is "seen" by many User Agents (text-browsers, search-engines, etc.). This shows how important it is for a document to make sense at the lowest level.

It is even worse for screen-reader users because products like Jaws support CSS and Javascript (to some extent), which means these users cannot access the content of the hidden sections styled with "display:none". They can tab through the Tabs, they could trigger the behavior and then try to navigate down the page, but it is far from intuitive since there is nothing spoken to them and also because the content comes in the wrong sequence.

Sighted users can have the very same experience by only disabling CSS. In visual browsers, only the content related to the first Tab shows, and there is no visual clue that the list items can trigger a behavior, revealing more content.

Enhanced version

The idea is to add some extra code to the "out-of-the-box" version to somehow address the main problems.

We replace the original code with the following, which includes A elements, inline events and named anchors:

<ul class="TabbedPanelsTabGroup">
<li class="TabbedPanelsTab" tabindex="0"><a href="#Content1" onclick="return false">Tab 1</a></li> <li class="TabbedPanelsTab" tabindex="0"><a href="#Content2" onclick="return false">Tab 2</a></li> <li class="TabbedPanelsTab" tabindex="0"><a href="#Content3" onclick="return false">Tab 3</a></li> <li class="TabbedPanelsTab" tabindex="0"><a href="#Content4" onclick="return false">Tab 4</a></li> </ul>
<div class="TabbedPanelsContentGroup">
<div class="TabbedPanelsContent"><a href="#null" name="Content1" id="Content1"></a>Content for Tab 1</div> <div class="TabbedPanelsContent"><a href="#null" name="Content2" id="Content2"></a>Content for Tab 2</div> <div class="TabbedPanelsContent"><a href="#null" name="Content3" id="Content3"></a>Content for Tab 3</div> <div class="TabbedPanelsContent"><a href="#null" name="Content4" id="Content4"></a>Content for Tab 4</div> </div>

This doesn't make the the code looks any better or doesn't even help regarding semantics, but at least the document now makes more sense for a few users. Visit Page 2 and disable support files to see the difference this makes regarding Accessibility.

Note: the HREF attribute in the named anchors is there to make sure Internet Explorer users can tab through links past these elements (IE bug).

Better version

To create a better version we simply start with a more semantic markup:

<div id="wrapper">
<h2>Tab 1</h2>
<div>Content 1</div>
<h2>Tab 2</h2>
<div>Content 2</div>
<h2>Tab 3</h2>
<div>Content 3</div>
<h2>Tab 4</h2>
<div>Content 4</div>
</div>

Instead of using attributes in every opening tag, we wrap all elements inside one single DIV with an ID. From there, an unobtrusive script uses only this hook to do all the heavy lifting. Visit Page 3 to see the difference.

Best version

The big plus of this version is that the DIVs are kept in the flow and grow depending on their content.

Because of this, I believe most people will see this version as the the best of all four, but in fact it is far from perfect. With CSS off and JS on, we have more or less the same issue as with the Spry version - it makes keyboard navigation confusing. So to give screen-reader users a better experience we give them a way to turn the behavior off. Visit Page 4 to see for yourself.

Browser support

If you read this article up to here, you're ready to hear more bad news about Spry "tabbed-panels". So here it is:
they do not work in Internet Explorer 5 (both Windows and Mac versions). The problem is not just that they don't work, it is that they do not degrade nicely. The Tabs show as Tabs, but the content for all the different Tabs is placed within the same panel. Worse, in IE Mac, an alert box pops up to alert users of script errors.

Wrap up

Our markup makes perfect sense at the lowest level (with JS and CSS off), our unobtrusive script ensures the separation of the two layers (content and behavior) and better browser support. Most important: we did not achieve "progressive enhancement" at the expense of screen-reader users.

Keep it Meaningful, Clean and Functional!