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.
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:
- Make sure that the browser understands the DOM methods I will be using.
- Make sure that there is an element with the ID “imagegallery.”
- Get the list with the ID “imagegallery.”
- Get all the links in the list and loop through them all.
- Add the
onclick
event handler to each link, pointing it to theshowPic
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 <!-- times out MAR2013 -->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.
Hi, it’s usefull article, i will say thanks… 🙂
If you liked the article and want to read more, definitely check out Jeremy’s book, DOM Scripting. He didn’t plug the book, and most people have heard of the book, but this article is a great example of what you can find in the book.
-Chasen
I hate adding JS and it messing up my page and making it look horrid.
It would be great to use this method and then link to a page saying how JavaScript is required to use a function for example.
Have ordered the book 🙂
The “Behaviour”:http://bennolan.com/behaviour/ library greatly simplifies this type of separation. Standard CSS selectors are used to apply javascript behavior. The image gallery separation example of the article condenses to this (not tested):
var myrules =
{
‘#imagegallery a’ : function(element)
{
element.onclick = function(element){ return showPic(element); }
}
};
Behaviour.register(myrules);
Wow, this article makes a lot of sense, and gives me a new way of looking at things for web pages and web art. I am a little confused about the object module stuff, but you have sparked my curiousity enough with a more effecient way of doing things that I must learn more.
Ted, you’re quite right about the Behaviour library. I especially like the motivation behind it. From the website:
“It’s great to see public uptake of these technologies – but it worries me to see the influx of script tags and onclick attributes into webpages.”
It’s also nice and lightweight.
The usual caveats apply: make sure you understand the code, and be aware of any cross-browser issues. But yes, Behaviour is well worth checking out.
It’s worth remembering that onLoad only fires when all elements of the page have loaded; on pages where there are many graphics, etc., there can be a substantial lag between when controls are loaded and when they become accessible.
“Dean Edwards”:http://dean.edwards.name/weblog/2006/06/again#comment5338 has a cross-browser solution which should give this type of javascript code management an extra level of useability.
Nice to see this technique explained in an ALA article. I have been using Behaviour for a little while and love it. It is nice to see an explanation of how to code it ” by hand”, so to speak.
Thank you for this good article. It is well written and explains in a few words the reasons for switching to this “new javascript”.
I enjoyed reading it as it is a topic I’m very interested in. For those interested, I wrote two Javascript “includes” (object in fact): an events manager, and a CSS styles manager; those can be found here:
http://yves.gablin.club.fr/gablin.php?page=pc_javascript
Yves.
You don’t always have to do your separation at the client level if it’s more work than it’s worth. A shining example is the Ruby on Rails framework which produces seemingly nasty inline JS hooks. It’s okay, though, because the code RoR generates for your is irrelevant in a management aspect, just as long as it works. This is because the generators already provide the separation for you. Setting up the generators to write the JS to a main
I’ve read the Bible. (Twice!) Doesn’t even come close to this!
This must be the greatest piece ever written in the history of mankind.
I don’t know (cause I can’t read) but this could well be one of the best articles ever written.
Greatest article ever.
Hi. It’s a useful article. Thank you.
Hi. Useful article. Thanks.
Great stuff.
Great stuff.
I liked this one.
Super duper macho mucho!
Really great.
Just great.
I think we will win this battle called web standards with great people like you Jeffrey.
“How the Web will Be Won” by Daniel L:
1. Time vs. Money. Though the people who are trying to ruin the web have a lot of money. We have more time than they’ll ever have.
2. Stamina vs. Money. After a few years of struggle people who are only in things for the money tend to give up if they meet strong and persistent resistance. Thus, we must never stop harassing these people for longer than a short time (like 10 hours).
3. Simplicity vs. Money. Money bastards will not simplify the world because common knowledge is not desirable from a business perspective. Thus, we must make it simpler, while they will continue to complicate things.
“How the Web will Be Won” by Daniel L:
1. Time vs. Money. Though the people who are trying to ruin the web have a lot of money. We have more time than they’ll ever have.
2. Stamina vs. Money. After a few years of struggle people who are only in things for the money tend to give up if they meet strong and persistent resistance. Thus, we must never stop harassing these people for longer than a short time (like 10 hours).
3. Simplicity vs. Money. Money bastards will not simplify the world because common knowledge is not desirable from a business perspective. Thus, we must make it simpler, while they will continue to complicate things.
Rad wrote:
bq. You don’t always have to do your separation at the client level if it’s more work than it’s worth. A shining example is the Ruby on Rails framework which produces seemingly nasty inline JS hooks. It’s okay, though, because the code RoR generates for your is irrelevant in a management aspect, just as long as it works.
I respectfully disagree. It makes life easier for the developer at the expense of the user. Ruby on Rails (in its current incarnation) will use inline event handlers tied to pointless internal links (href=”#”). This means that user-agents that aren’t JavaScript capable get nothing, nada, zip. Far from being a shining example, this is the one glaring problem with RoR. It may be irrelevant, as you say, in a management aspect but it sucks for the person trying to use your application.
Fortunately, the Ruby on Rails community is vibrant and responsible enough to “plug this hole”:http://opensource.agileevolved.com/trac/wiki/UnobtrusiveJavascript .
Good to see an unobtrusive Javascript update to the image gallery script which I’ve used on several sites.
A quick note: for readers trying to figure out what showPic is referencing at the end of the script, check out the original article Jeremy wrote two years ago.
Thank you for the article. I’ve already seen this way of using CSS classes to get elements and modify them (i used it to make rounded image corners for blocks on my site).
I simply put my function before tag. Isn’t it a simplier way? You don’t need any images or flash objects to change DOM.
Along the lines of Behaviour is “event:Selectors”:http://encytemedia.com/event-selectors/, which I’ve used for a recent project. It follows the idea of Behaviour but eliminates some of the extra syntax you need. Definitely worth checking out.
Great article!
I’d like to add that Dean Edwards script to add events on DOM load also avoids memory leaks in Internet Explorer, unlike the Simon Willison version which is recommended in the article.
Similarly, I would recommend people looking into “Dean’s article on addEvent()”:http://dean.edwards.name/weblog/2005/10/add-event2/ (though I personally prefer Tino’s version).
What a great, simple example of semantic markup goodness. Clean markup, looking great, doing something cool. Just perfect!
Great article, but I found an article on SitePoint regarding “opening new windows in a standards-compliant way”:http://www.sitepoint.com/article/standards-compliant-world which uses the “rel” attribute rather than the CSS class in order to specify some behaviour.
This neatly leaves out the javascript references in the HTML, but doesn’t conflict with any visual styles you want to apply to an element, so further separating style and behaviour.
May I recommend the awesome “jQuery”:http://www.jquery.com/ library for all of your unobtrusive javascript needs. It is even lighter than Behavior and can get more done in fewer lines of code.
I’ve given the unobtrusive javascript approach a shot in a few of my web applications, but in one particular app, there was a *HUGE* DOM, and I needed to be able to add behavior to any arbitrary node. There was a noticeable lag when it walked the DOM @ load time, which is especially bad because the browser appears to be frozen during this time.
In this case, I opted for the inline approach. And for some of the
Thanks for another great article on seperation. This method has proven to be the way to go for web development.
In response to people who have linked to Javascript libraries that utilize CSS selectors to access DOM objects, I’d like to mention that “Prototype 1.5”:http://dev.rubyonrails.org/browser/spinoffs/prototype now has a useful CSS selector function, $$().
Prototype is the *original* Javascript library that others are dependant on. Behaviour, Script.aculo.us, and Event:selector, and Moo.fx are examples.
As an illustration of the code, and demonstration of the power of Prototype, I’ve created a “demo of sorting a table”:http://www.deletem3.com/2006/04/01/sorting-a-table-with-javascript/ with the Javascript Prototype library and it’s CSS selector function. The demo uses no inline Javascript or CSS.
I’ve been using unobtrusive JS for about 2/2.5 years now. It’s actually what I did pretty much from the beginning after having learned XHTML/CSS and its advantages as well as the doctrine that is seperation. That was probably four years ago and whenever JS was added (I try to limit it’s use as much as possible) I added it through an external JS file.
But I do have to say that I really appreciate your article, it’s especially good for all the people who think AJAX is the best think to happen. Ever.
I hope some will learn the wrong of their ways, because if you’re paranoid like me then you’ve only got JS enabled on sites you trust.
Quickly looking over your updated prepareGallery() function, wouldn’t the following revision of the ‘for’ loop be (slightly) more efficient?
for (var i = 0, link; link = links[i]; i++) {
link.onclick = function() {
return showPic(this);
};
}
Personally, I find this format of iteration in JavaScript to be easier to follow too. Just a thought…
Using CSS selectors for javascript hooks is really unnecessary. The DOM makes it possible that you could even just look for the href’s and assign the proper function based on the href.
An _imperfect_ example is here: “http://www.vestedventures.com/consulting/services.html”:http://www.vestedventures.com/consulting/services.html
If javascript is not supported, the content is one long column, and the right hand links will jump to the section desired by anchor name. When javascript works, the javascript is parsed, and swaps the content to the proper screen. All javascript on this entire site is unobtrusive. (_Note:_ I am not claiming it is best possible way to do the things on the site, nor is it even pretty)
However, I do agree that the method promoted in this article is better than much of what is on the web. It can be improved upon though.
Do you want all links that begin with a different domain to open in a new window? check the indexOf the href for the domain, if it’s not in there, open a new window.
Of course, if you are using a class to style the link, for instance all external links are a differnet color, then you could use that aspect of the anchor as your hook.
But overall, use CSS selectors for presentation. Use the DOM and javascript for behavior.
At least those are my $0.02 😉
Whoa there, Michael. I think you might be confusing CSS selectors with plain old attributes. These are CSS selectors:
.myclass
#myid
These are attributes:
class=”myclass”
id=”myid”
Now, CSS does use attributes like class and ID for its selectors, but that doesn’t mean that class and ID are tied to CSS. They are HTML attributes which means that they should be used to markup content as being uniquely identified or belonging to a certain group (class). These attributes existed before CSS.
So, I’m not using any CSS selectors. I’m making use of the document’s semantic structure. This is very similar to what CSS does but CSS does not have exclusive rights to those attributes.
Jeremy, I wasn’t trying to argue semantics…
Typical use of the class atribute is for further use as a css selector.
And again, I feel your suggestion is better than much of what is on the web.
It’s just that if you use the attribute class as a javascript hook, you are blurring the lines between behavior and presentation, instead of separating those layers.
Look not further than “this article”:http://www.alistapart.com/articles/scripttriggers/
And javascript can be unobtrusive using other methods which may not be confusing to the anyone who has to edit the code later.
That was my point.
Michael wrote:
“Typical use of the class atribute is for further use as a css selector.”
That’s true, but don’t confuse “typical use” with “only use” or even “correct use”. The class attribute exists to add semantic meaning. It can be repurposed by CSS. It can also be repurposed by JavaScript and the DOM. Neither use is more correct than the other. Both are valid. Both are building on top of the inherit semantic value of the attribute.
It’s not that I “use the attribute class as a JavaScript hook”, I *repurpose* the attribute class (or ID) as a JavaScript hook… or a CSS hook, depending on whether I’m trying to enhance behaviour or presentation.
Classes (and IDs) aren’t owned by CSS. Neither are they owned by JavaScript — they belong to the markup. But both CSS and JavaScript can legitimately use them as hooks.
I understand your point that one shouldn’t add *unnecessary* classes or IDs just for the sake of JavaScript, but that’s equally true of CSS: one shouldn’t (theoretically) add classes or IDs just to act as hooks for presentation (for the same reasons you cite).
…although I agree that this is far from new hotness. I’ve been _*attempting*_ do this for a few years now. I find that it helps me not rely on JS as a crutch. How many times have you made a page that wouldn’t work at all without a little JS? I’ve made more than my fair share.
This method lets you design an entire site that just works. Then, once you are done with that, you can go back and dynamically add any behaviors. I’ve actually started treating CSS the same way, as it helps me use semantically correct markup to see everything un-styled…
For those who want to know what else could you do with behaviour, I’ve utilized Behaviour to do form validation. It even has a quite “nice” balloon effect as notification mechanism. Further, I’ve add this behavioral validation into GTFW web framework, which made it support both server dan client validation. No fancy AJAX thing yet, but it indeed features graceful degradation. 🙂
Introduction and demo URL can be found “here”:http://blog.neofreko.com/index.php/2006/05/03/even-nastier-behaviour-balloon-notification-effect/
Great article. However I would say that the benefit of separating content from style is all about making managing the underlying content easier.
All separation should answer these questions in the affirmative:
Does it make my job as a web designer easier, so that I can go play outside before it gets dark.
Will it make the job of the next person who touches the code easier, so that he/she doesn’t have to call me up and complain whilst I’m outside playing.
The Article was very interesting and nice to read. From now on I will use this technique where its usefull.
I like this idea of writing code.
Thanks for that article.
Even I don’t know much of Java, but this article gives me some ideas.
As a long-time web developer, it’s great to see JavaScript finally maturing. It’s been just a hack for far too long. The web just gets more exciting every day!
I love to make things prettier, I just can not believe I heard a guy say pretty anything , even still a great couple of tricks on how to spice up the pages. Has been along time since I did any work in java script and on the next site I do use it I am going to have to give them a try, since most java scripts I make are ugly.
Jeremy wrote:
bq. I respectfully disagree. It makes life easier for the developer at the expense of the user. Ruby on Rails (in its current incarnation) will use inline event handlers tied to pointless internal links (href=”?#”?). This means that user-agents that aren’t JavaScript capable get nothing, nada, zip. Far from being a shining example, this is the one glaring problem with RoR. It may be irrelevant, as you say, in a management aspect but it sucks for the person trying to use your application.
Separating your JavaScript doesn’t solve this, it just makes it more natural. It’s quite easy to add a fallback URL in Rails.
@<%= link_to_remote 'Link', { :url => ajax_url, :update => ‘box’ }, { :href => non_ajax_url } %>@
And nothing is stopping you from using pointless internal links when your JavaScript is located in an external file or @
I found this article extremely useful as I was not previously aware of the ability to remove inline event handlers in preference of this more elegant solution.
I’d highly recommend Jeremy’s book on the subject for anyone who is familiar with JavaScript but new to this way of doing things:
“DOM Scripting: Web Design with JavaScript and the Document Object Model”:http://www.friendsofed.com/book.html?isbn=1590595335
A very nice article, I really like unobtrusive javascript,
Thank you.
Muhammad Hassan
http://www.badrit.com
A very nice article, I really like unobtrusive javascript,
Thank you.
Muhammad Hassan
http://www.badrit.com
This is such an excellent idea. After having read the original article, I bought the book, and have used this technique wherever possible since.
Good to see an unobtrusive Javascript update to the image gallery script which I’ve used on several sites.
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.
Nice topic Ted,
Its open my eyes once again
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.