Digital Web Magazine

The web professional's online magazine of choice.

Separating behavior and structure

Got something to say?

Share your comments on this topic with other web professionals

In: Columns > Keep It Simple

By Peter-Paul Koch

Published on April 14, 2004

In my previous column I confessed a fear for "accessibility zealots" who really are anti-JavaScript zealots. More than once I’ve encountered a hostile reaction to the idea of using any JavaScript at all, although fortunately this attitude remains confined to the fringes of Web development land.

These anti-JavaScripters make some good points, but they are not well informed of recent advances in JavaScript theory. The time has come to concede that in some respects they are completely correct, to propose a change of coding habits, and to end the "JavaScript is Evil" nonsense once and for all.

We’re going to separate behavior and structure. That should convince even the die-hards.

The anti-JavaScript school of thought

First a bit of history. Initially the CSS revolution didn’t get along well with JavaScript. There were two reasons for this:

  1. It is not possible to create sliding layers and such in CSS. Since many people thought a site had to be complex to be good, and since sliding layers are awesomely complicated, old school scripting retained its popularity.

  2. On the other side of the fence, theory hadn’t yet advanced sufficiently to take JavaScript into account. Pioneers were busy separating presentation and structure, and exploring the frontiers of CSS. Incorporating JavaScript into the new way of thinking was not a top priority.

Combined, these factors ensured that nothing changed much. Web developers continued to use traditional JavaScript junkyard libraries that niftily made layers perform all the functions of a normal OS window—without, of course, opening a new window. That would be cheating.

Since these scripts were so complicated, and the interfaces they created so pointedly useless, the CSS pioneers largely stopped using cutting edge JavaScript. They did so in an informal, non-dogmatic way, and at that point in time they were right. Cutting edge JavaScript had run amok.

This essentially temporary measure led to the birth of the anti-JavaScript school of thought, which in due time split into a moderate and a radical wing.

Anti-JavaScripters seem to have four issues with JavaScript—though I never found an article that actually states all issues clearly and concisely:

  1. Usability. There are quite a few irritating JavaScript effects. Popups, status bar messages, sliding layers and such can be extremely annoying. This is not an argument against JavaScript as a whole, though. The best way to deal with these scripts is not to use them.

  2. Accessibility. Some users don’t have JavaScript (enabled). I think this issue is in the process of being solved. From a fundamental problem— why should I make my site accessible?—it has become a technical one: how should I make my site accessible?

  3. Ugliness. Even useful scripts may require very ugly code. This really means that behavior and structure aren’t separated properly, which is the subject of this column.

  4. Overlap. CSS can take over some of JavaScript’s traditional functions, like mouseovers and foldout menus. I find this idea interesting and I’ll discuss in my next column.

In this column I offer a short, guided tour of modern JavaScript thinking, and a simple innovation in page coding techniques. I hope to show you that these issues surrounding JavaScript use—in modern XHTML/CSS sites—can be solved, and that there are no fundamental reasons not to use this beautiful language.

Changing document structure

JavaScript is a powerful addition to otherwise accessible XHTML/CSS pages. It serves to enhance a site’s usability. Moreover, it does so by subtly changing the XHTML structure.

Simon Willison, especially, has done great work on this concept. His Enhancing Structural Markup with JavaScript gives some simple, useful examples of changing XHTML structures with JavaScript to add small bits of usability to your site, without sacrificing accessiblity.

When you go through his examples you’ll notice that they aren’t flashy. They don’t move or shake anything, they go light on the interfaces, they depend on solid, structural markup, and they singularly lack any "impress the newbies" wow-factor.

That’s why I like them so much. Simon’s scripts just do what needs to be done, and they do it by modifying the document structure ever so slightly. In addition, they don’t require 40K libraries and flocks of useless objects.

My own Usable Forms script is based on similar principles, though both the script itself and the changes it makes in the document structure are more complex than Simon’s examples.

Unobtrusive scripting

Stuart Langridge’s Unobtrusive DHTML makes some powerful points about what DHTML menus should and shouldn’t do.

I paraphrase Stuart’s ideas as follows:

  1. Usable. A script should be unobtrusive to the user. No flashy stuff or sliding layers, just a small usability benefit that helps users make sense of a site instead of hindering them.

  2. Accessible. A script should be unobtrusive when it doesn’t work. The site shouldn’t depend on the script.

  3. Easy to implement. A script should be unobtrusive to Web developers. Typically, a Web developer should only have to include a script and to add a class or id to one or more XHTML elements, which the script interprets as: "Deploy the behavior here".

Stuart’s third idea of unobtrusiveness takes a very important step, and Simon’s article takes the same step. They separate behavior and structure.

Nonetheless I feel that Simon and Stuart don’t place enough emphasis on this separation, which is why I’m going to explain it further. Besides, I’d like to remind you of a similar step we took four years ago.

The <FONT> tag approach

Back when pioneers started explaining the advantages of CSS, they used <FONT> tags as symbols of what was wrong with old-school HTML. These tags were extremely ugly, they had to be repeated in every <TD> so that their number grew beyond control, and they were easy to replace by CSS.

That’s why they made an excellent starting point for the revolution. In fact, when Netscape 3’s market share had dropped sufficiently to start using CSS, I summarily abolished <FONT> tags in the company I worked for. Then I explained how to replace them.

Of course, back then we didn’t really know how to go on from there. Browsers weren’t what you’d call cooperative, and the fine points of CSS’s more complex modules still eluded us. We moved font definitions to CSS files, but continued to use table-based layouts.

Nonetheless I’d succesfully introduced the concept of CSS. Though it took us years to work out the details, we’d made a start. I assume other Web developers started in comparable ways.

I propose making a similar start for JavaScript.

Cleaning up the mess

Do you remember mouseover menus from hell?

<TR VALIGN=TOP><TD WIDTH="130" VALIGN=CENTER><IMG
	SRC="arrow.gif height="32" width=130
	name="clouds2"><TD><A HREF="clouds.html"
	onMouseOver="setMouseOvers(this,'clouds','clouds2',false)"
	onMouseOut="removeMouseOvers('clouds','clouds2',4)"
	><IMG SRC="clouds.jpg" NAME="clouds"
	width="125" HEIGHT="73"></A></TD>
<TR VALIGN=TOP><TD WIDTH="130" VALIGN=CENTER><IMG
	SRC="spacer.gif" height="5" width=130><TD 
VALIGN=CENTER></TR>
<TR VALIGN=TOP><TD WIDTH="130" VALIGN=CENTER><IMG
	SRC="arrow.gif height="32" width=130
	name="turtles2"><TD><A HREF="turtles.html"
	onMouseOver="setMouseOvers(this,'turtles','turtles2',false)"
	onMouseOut="removeMouseOvers('turtles','turtles2',4)">
	<IMG SRC="turtles.jpg" NAME="turtles"
	width="125" HEIGHT="73"></A></TD>
[etc]

Structural thinking prevailed. Out went tables-for-layout and spacer gifs, in came simple XHTML:

<ul>
<li><a href="clouds.html"
	onmouseover="setMouseOvers(this,'clouds',false)"
	onmouseout="removeMouseOvers('clouds',4)"><img
	src="clouds.gif" alt="Clouds"
	name="clouds" id="clouds" width="125" height="73"
	/></a></li>
<li><a href="turtles.html"
	onmouseover="setMouseOvers(this,'turtles',false)"
	onmouseout="removeMouseOvers('turtles',4)"><img
	src="turtles.gif" alt="Turtles"
	name="turtles" id="turtles" width="125" height="73"
	/></a></li>
[etc]

This XHTML code snippet doesn’t specify the presentation of the link list, which is as it should be. Presentation is CSS’s job, not XHTML’s.

The code does specify the behavior of the link list, though. In fact, the ugly behavior definitions all but jump out and hit us in the face. Take a good look at them:

onmouseover="setMouseOvers(this,'turtles',false)"
onmouseout="removeMouseOvers('turtles',4)"

Is this clean code that tightly fits into a modern XHTML page? Is it full of rich structural meaning?

Let’s get rid of the junk and see what happens:

<ul id="mouseovers">
<li><a href="clouds.html"><img
	src="clouds.gif" alt="Clouds"
	width="125" height="73" /></a></li>
<li><a href="turtles.html"><img
	src="turtles.gif" alt="Turtles"
	width="125" height="73" /></a></li>
[etc]

That’s much better, don’t you think? Now the XHTML creates structure, and structure only. No presentation. No behavior, either.

Separating behavior and structure

I propose to separate behavior and structure. Right here, right now.

I call upon all Web developers to stop writing JavaScript instructions in XHTML files.

Just as font definitions belong in the presentation layer, in a CSS file, mouseover definitions belong in the behavior layer, in a JavaScript file. Neither should clutter up the XHTML structure layer.

The process flow is very simple:

Illustration: Remove JavaScript from  page until no JavaScript is left

Once you’ve done this you have put the behavior layer where it belongs, in an external .js file.

This move has exactly the same advantages as putting the presentation layer in an external .css file. In addition to creating cleaner code, it allows you to easily modify the behavior layer across your site.

If you want your header graphic to display mouseover behavior, too, you just add a few lines of code to the .js file. This is far more efficient than manually inserting onmouseover and onmouseout event handlers into every single content page.

Of course you have to connect this newly created behavior layer to the XHTML structure layer, and mark some elements as "having behavior":

  1. You need a <script> tag that includes your .js file in the page, just as a <link> tag includes your .css file:

    <script src="mouseovers.js" type="text/javascript"></script>
    
  2. You need a way of saying "Add the behavior here", just as CSS requires a way of saying "Use these styles here". In the mouseover example the id="mouseover" fulfills this function, but you could also use other attributes, or add behavior to, say, all <span>s that don’t have a class.

The last point requires you to structure your XHTML carefully, but you’d have to do that anyway.

Examples

Most JavaScript instructions in XHTML files are inline event handlers like the ones in the mouseover example. Removing these inline event handlers is therefore the most important step you have to take.

Of course you have to replace them with code structures that serve the same purpose—but that don’t mess up your XHTML—just as you had to replace <FONT FACE=verdana" SIZE=3> with p {font: 12px verdana;}.

You have to define your event handlers in other, cleaner ways. To help you understand the basics of this move I give four examples.

(To fully understand these examples you might have to upgrade your knowledge of JavaScript event handlers, just as four years ago you had to master the basics of CSS to get rid of the <FONT> tag. Changing coding habits means learning new things.)

Example 1: To assign mouseover behavior to our example list, use the following code. This code goes, of course, in your included JavaScript file.

function initMouseovers()
{
	var nav = document.getElementById('mouseovers');
	var imgs = nav.getElementsByTagName('img');
	for (var i=0;i<imgs.length;i++)
	{
		imgs[i].onmouseover = mouseGoesOver;
		imgs[i].onmouseout = mouseGoesOut;
	}
}

Running this function sets the mouseover behavior without using any inline event handlers. When the user mouses over any image in <ul id="mouseovers"> the mouseGoesOver() function is called. When the user mouses out again, mouseGoesOut() is called.

You still need the code for these two functions. I didn’t include it here since it would take up too much space. Instead, you can study the example script I prepared on my own site. It’s simple, it works in all modern browsers, and it doesn’t use a single inline event handler.

Example 2: To assign a behavior to all <span>s that don’t have a class, do:

function initSpanBehavior()
{
	var spans = document.getElementsByTagName('span');
	for (var i=0;i<spans.length;i++)
	{
		if (spans[i].className) continue;
		spans[i].onsomeevent = doSomething;
	}
}

Example 3: You still have to execute the function initMouseovers() or initSpanBehavior() when the page has been loaded. Don’t do

<body onload="initMouseovers()">

It mixes up structure and behavior by adding a JavaScript function call to your XHTML, where it doesn’t belong. This instruction should be moved to your included JavaScript file, too:

window.onload = initMouseovers;

To execute both initialization functions, do

window.onload = function () {
	initMouseOvers();
	initSpanBehavior();
}

(There are some problems with the window.onload approach, but they are technical in nature, not conceptual. The code above illustrates the correct concept. Besides, it’s safe enough for simple pages.)

Example 4: Chris Heilmann provides the final example. His Javascript navigation - cleaner, not meaner explains how to assign DHTML behavior to an orderly, simple list-item navigation. Chris doesn’t treat the actual DHTML, but concentrates on gracefully separating behavior and structure while retaining overall accessbility.

(I mercilessly attacked Chris when he wrote bad articles, so it’s only fair that I praise him when he writes good ones.)

He thus advocates the same change of coding habits as I do. Nonetheless I feel that Chris, like Simon and Stuart, doesn’t give the fundamental idea enough emphasis.

Taking the first step

In my opinion, recent advances in JavaScript theory call for the removal of the event handlers that some Web developers—and all WYSIWYG editors—deploy in large masses in their XHTML files, where they don’t belong.

Moving them to .js files separates behavior and structure, just as the removal of <FONT> tags started the separation of presentation and structure.

Above I listed four issues with JavaScript. Removing all inline event handlers will largely solve the Ugliness issue. Not using silly scripts solves the Usability issue, and the Accessibility issue is being addressed, though not yet solved.

I hope this will convince moderate anti-JavaScripters that JavaScript is on the move towards integration in accessible XHTML/CSS pages, and that there is no fundamental reason to avoid it.

I also invite them to take the first step, to try adding a minor, harmless behavior layer to a site, to practice separating behavior from structure and making informed accessibility decisions.

But what about the overlap issue? What about CSS being able to mimic many traditional JavaScript functions? In other words, what about separating behavior and presentation? That’ll be the subject of my next column.

Got something to say?

Share your comments  with other professionals (12 comments)

Related Topics: DOM, Scripting

 

Peter-Paul Koch is a freelance web developer, writes and maintains the Quirksmode.org site. He is also an Administrator of the WDF and WDF-DOM mailing lists.

Media Temple

via Ad Packs