Behavioral Separation
Issue № 218

Behavioral Separation

Breaking up is hard to do. But in web design, separation can be a good thing. Content, style, and behavior all deserve their own space.

Article Continues Below

Style guide#section2

One of the greatest advantages to designing with Cascading Style Sheets is the potential for separation of style and content.

You could style an entire website using nothing but inline style declarations:

<p bold; color: red;">This text is important</p>

But then you might as well use <font> tags. It makes more sense to keep style information in a separate file and add semantically sensible hooks into your markup:

Markup: <p class="important">This text is important</p>

CSS: p.important { font-weight: bold; color: red; }

That makes everybody’s life easier. It’s easy for the designer to tweak the styles—like changing important text from red to blue. It’s easier for the writer to edit the text without wading through inline style declarations. It’s easier for the visitor who doesn’t have to download unnecessarily bloated pages.

What’s good for CSS is good for JavaScript. Unfortunately, a lot of JavaScript functionality is found embedded within markup.

Everything is superficially intertwingled#section3

Suppose you want to add some behavior to a particular link. You could use what’s known as the javascript: pseudo-protocol:

<a href="javascript: doSomething();">click for fun</a>

That’s a short-sighted approach. User agents that don’t support JavaScript will choke on that href value. A more common approach is to use event handlers in combination with a meaningless href value:

<a href="#" >click for fun</a>

That’s slightly better but it’s semantically meaningless. Why mark up a piece of text as a link unless it goes somewhere?

<a href="arealpage.html" return false;">click for fun</a>

Now we’re getting somewhere. The link makes sense even if JavaScript isn’t enabled (and, for the first time, the link is spiderable). But the problem remains that the event handler is mixed in with the markup. Inline event handlers are the JavaScript equivalent of inline style declarations. Fortunately, the event handlers can be removed and placed in an external file, just as you would do with CSS. And, just as with CSS, you can add hooks to your markup to target the elements you want to play with:

<a href="arealpage.html" class="fun">click for fun</a>

In an external JavaScript file, you could now write a script to find all the links that have a className of
“fun” and have them execute a function—doSomething()—when they are clicked.

Separating out behavior from markup like this is called unobtrusive JavaScript.

Enough theory. I’m going to apply this technique to a real-world example.

Rogue’s gallery#section4

Two years ago, I wrote an article for A List Apart on building a JavaScript image gallery. The JavaScript in that article works fine, but take a look at the markup (line wraps marked » —Ed.):

<ul>
  <li><a showPic(this)"
  href="images/bananas.jpg" »
  title="A bunch of bananas »
  on a table">some bananas</a>
    </li>
  <li><a showPic(this)"
  href="images/condiments.jpg" »
  title="Condiments in a »
  Chinese restaurant">two bottles</a>
    </li>
  <li><a showPic(this)" 
  href="images/shells.jpg" »
  title="Seashells on a table"> »
  some shells</a>
    </li>
</ul>

Those repetitive event handlers are intrusive. I could replace them with class attributes (line wraps marked » —Ed.):

<ul>
  <li><a class="gallerypic" »
  href="images/bananas.jpg" »
  title="A bunch of bananas on a table">some bananas</a>
    </li>
  <li><a class="gallerypic" »
  href="images/condiments.jpg" »
  title="Condiments in a Chinese restaurant">two bottles</a>
    </li>
  <li><a class="gallerypic" »
  href="images/shells.jpg" »
  title="Seashells on a table">some shells</a>
    </li>
</ul>

But that would be equally repetitive. I wouldn’t do that if I wanted to style every item in the list, so there’s no need to do it when I want to add a behavior to every item in the list. Instead, I can simply add a unique id to the list (line wraps marked » —Ed.):

<ul id="imagegallery">
  <li><a href="images/bananas.jpg" title="A bunch of »
  bananas on a table">some bananas</a>
    </li>
  <li><a href="images/condiments.jpg" title="Condiments »
  in a Chinese restaurant">two bottles</a>
    </li>
  <li><a href="images/shells.jpg" title="Seashells on a »
  table">some shells</a>
    </li>
</ul>

Now I need to write a function to add the event handlers externally.

Separation anxiety#section5

I’ll write a function called prepareGallery. This function will use the Document Object Model to find the links in the document I want. This is possible with the methods getElementById and getElementsByTagName:

document.getElementById("imagegallery").getElementsByTagName("a");

Those methods work like selectors in CSS. It’s the equivalent of combining id and element selectors:

#imagegallery a

Here’s what I want to do:

  1. Make sure that the browser understands the DOM methods I will be using.
  2. Make sure that there is an element with the ID “imagegallery.”
  3. Get the list with the ID “imagegallery.”
  4. Get all the links in the list and loop through them all.
  5. Add the onclick event handler to each link, pointing it to the showPic function.

Here’s how that translates into JavaScript:

function prepareGallery(){
  if( document.getElementById &&
      document.getElementsByTagName ){
    if( document.getElementById( 'imagegallery' ) ){
      var gallery = document.getElementById( 'imagegallery' );
      var links = gallery.getElementsByTagName( 'a' );
      for( var i=0; i < links.length; i++ ){         links<i>.
          return showPic(this);
        };
      }
    }
  }
}

Now that I’ve written my function, all I have to do is run it. But there’s a problem. I can’t simply execute the function like this:

prepareGallery();

If I do that, the function—which is in an external file or in the head of my document—will run before the rest of the document has finished loading. The DOM methods won’t work because there won’t be any Document Object Model. Without a complete document, there can’t be a corresponding model.

I need to wait until the entire document has finished loading. Fortunately, the loading of the document triggers an event, namely the load event of the window object. I can use the corresponding onload event handler, window.onload, to assign the prepareGallery function to this event:

window.onload = prepareGallery;

Rather than hogging the onload event for this one function, it’s better to use something like Simon Willison’s excellent addLoadEvent function, which allows you to queue up functions that you want to trigger when the document finishes loading:

addLoadEvent( prepareGallery );

Trial separation#section6

Unobtrusive JavaScript is a relatively new idea. Try it out for yourself.

  • Begin with your content,
  • give it structure with semantically descriptive markup,
  • apply a presentation layer using CSS, and finally,
  • add a behavior layer with DOM Scripting.

Just make sure they all keep their distance.

57 Reader Comments

  1. This is such an excellent idea. After having read the original article, I bought the book, and have used this technique wherever possible since.

  2. I’m a relative css newbie… But I must say that this is very confusing to follow without seeing it all put together html and all. I know everyone here has tons of experience, but sample code (completed) really helps make the whole thing understandable.

    I could not find any file that shows how it would look finished. It seems a lot of these samples, beautifully annotated in pieces, but in the end… you’re left wondering, guessing, and not knowing exactly what to do.

    So while all the info is cool, the final big picture remains unclear to someone like me, with many years html experience, but not that much css. If anyone has a source html using this could you please let me know. much thanks!! and I really appreciate how everyone shares what they know. That is really wonderful.

  3. I appreciate the concept of unobtrusive JavaScript, I am constantly working on better techniques. The question is, when it isn’t a simple example how do you handle the increased amounts of conditions and work that have to be done?

    First, the example of the store inventory and paginating through pages of items via AJAX. In this example, an AJAX request would pull content for the container it would be loading into. Without JavaScript enabled, an HREF would request a the same template, but based on that request type would load additional files necessary for a full layout. Does every framework identify for the user what the request type was (AJAX, XML, HTML) so that conditionals may be written in each template? Is that the suggested solution in these situations? It seems cumbersome, how do you go about overriding the potentially large number of hrefs you want to hijack? Just apply a generic class to each?

    In addition to that, lately I have been writing a class to one of the main containers using JavaScript, such as ‘jsenabled’. Children of that container that have elements or effects dependent on JavaScript have declarations styled against that class. This works painlessly when your design is basic, but when you are working with a designer or client that likes complicated designs having to style things like a select box, then style its DHTML substitute starts to add a lot of work quickly.

    What are your thoughts and experiences on this? I always seem to work out a solution, but I wanted to pick the brains of some of the experts on preferred practices.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career