Keeping the hot side hot and the cold side cold

Written byAaron Gustafson. 15 comments

Aaron Gustafson

Aaron Gustafson runs a web consultancy, Easy! Designs, and is a member of the Web Standards Project (WaSP) and the Guild of Accessible Web Designers (GAWDS). He serves as Technical Editor for A List Apart, and has spoken at numerous conferences including An Event Apart and Web Directions.

Applying 1980s’ fast-food logic to JavaScript and CSS separation: techniques for keeping your presentation out of your scripts.

If, like me, you lived through the 1980s in the United States and watched any tele­vi­sion at all, you prob­a­bly recall a pre-​​Seinfeld Jason Alexan­der pranc­ing about, singing the won­ders of a new ham­burger from the golden arches: the McD.L.T.

The McD.L.T. (which stood for McDonald’s Let­tuce & Tomato) was a bril­liant con­cept: it quar­an­tined the hot ham­burger patty in one com­part­ment and the cold, crisp let­tuce and tomato in the other, leav­ing the con­sumer to com­bine the two halves for the full McD.L.T. ‘experience’.

Through this sep­a­ra­tion, McDonald’s was able to cre­ate a much more enjoy­able prod­uct and we, as web design­ers and devel­op­ers, can learn a lit­tle some­thing from this concept.

Sep­a­ra­tion is at the heart of the web stan­dards movement.

Sep­a­ra­tion of con­tent from pre­sen­ta­tion came first, and we began swap­ping FONT ele­ments for style sheets. The next major move­ment was the sep­a­ra­tion of con­tent from behav­iour, which urged us to write unob­tru­sive JavaScript. Unfor­tu­nately, the final mem­ber of the web stan­dards sep­a­ra­tion tri­umvi­rate – the sep­a­ra­tion of behav­iour from pre­sen­ta­tion – has yet to take hold, but the tide is start­ing to turn.

Where’s the beef?

JavaScript (and CSS, for that mat­ter) first became pop­u­lar as com­po­nents of DHTML. It was in the con­text of DHTML that styles and scripts first become entan­gled and, regret­tably, the knot they formed has proven par­tic­u­larly dif­fi­cult to untie.

As you know, DHTML was not a lan­guage unto itself, but rather an appli­ca­tion of JavaScript for manip­u­lat­ing the DOM, to gen­er­ate and alter both markup and styles on the fly. Here’s a ridicu­lously sim­ple exam­ple of early DHTML:

  1. <a href=“foo.html”;
  2.     style=“color:blue;”
  3.     onmouseover=“this.style.color=‘red’”
  4.     onmouse­out=“this.style.color=‘blue’”>Foo</​a>

Main­te­nance of code like this was a night­mare because any change in the behav­iour required you to muck about in the markup.

If tasked with cre­at­ing this same inter­face today, the obvi­ous choice would be to add

  1. a, a:link, a:vis­ited {
  2.   color: blue;
  3. }
  4. a:hover {
  5.   color: red;
  6. }

to an exter­nal stylesheet and avoid using JavaScript alto­gether; so, why didn’t DHTML coders do the same? Well, the likely answer is that CSS was so poorly under­stood at the time that the folks writ­ing DHTML weren’t aware of the other options avail­able to them. But we know bet­ter … don’t we?

It’s bet­ter here

Mod­ern JavaScript, even the unob­tru­sive sort, still employs the same basic means of style manip­u­la­tion. The only dif­fer­ence is that in today’s JavaScript, the STYLE attribute manip­u­la­tion is likely to exist in an exter­nal file, where you’ll find some­thing akin to this:

  1. for( i=0; i<objects .length; i++){
  2.   objects[i].style.dis­play = ‘none’;
  3. }

This exam­ple was taken from the JavaScript library used on the cur­rent Microsoft home­page, but you see this sort of code in prac­ti­cally every JavaScript library and tonnes of one-​​off scripts. I chose this par­tic­u­lar lit­tle code snip­pet because it intro­duces a known acces­si­bil­ity issue: most screen read­ers will not read con­tent that is hid­den using dis­play: none or vis­i­bil­ity: hid­den, whether it is writ­ten in your stylesheet or set via JavaScript.

Cur­rently, the best prac­tice for hid­ing con­tent in an acces­si­ble way is to absolutely posi­tion said con­tent way off the left-​​hand side of the page

  1. for( i=0; i<objects .length; i++){
  2.   objects[i].style.posi­tion = ‘absolute’;
  3.   objects[i].style.left     = ‘-999em’;
  4. }

But what if the best prac­tice was to change? It would be far eas­ier (and much more eco­nom­i­cal) to main­tain this sort of style infor­ma­tion in dec­la­ra­tions like this:

  1. .hid­den {
  2.   posi­tion: absolute;
  3.   left: -999em;
  4. }

We could then update our code to activate/​deactivate them as needed:

  1. for( i=0; i<objects .length; i++){
  2.   objects[i].add­Class­Name( ‘hid­den’ );
  3. }

Addi­tion­ally, if best prac­tices changed, we’d only need to update our CSS and not the JavaScript.
But how do we main­tain style rules asso­ci­ated with our scripts? That’s the $10 mil­lion question.

Do what tastes right

There are cur­rently only a hand­ful of options avail­able for sep­a­rat­ing pre­sen­ta­tion from behav­iour, but they fall into two broad cat­e­gories: exter­nal­is­ing and embedding.

Exter­nal­is­ing

Exter­nal stylesheets are prob­a­bly the most widely used form of stylesheet, and with good rea­son: they have the ben­e­fit of being cached, allow­ing them to be used across an entire site with­out incur­ring a down­load penalty as a user moves from page to page. (Many folks com­ing into JavaScript pro­gram­ming with a CSS back­ground also pre­fer this method because it’s more famil­iar to them.

When work­ing with exter­nal stylesheets in JavaScript, you have a few options. First, you can pack­age all of the styles your script requires into a sin­gle stylesheet. Any­one imple­ment­ing your script would then be required to include the CSS file when­ever they include your script:

  1. <script type=“text/​javascript” src=“WickedCool.js”></​script>
  2. <link rel=“stylesheet” type=“text/​css” media=“screen” href=“WickedCool.css” /​>

This approach gives you all of the ben­e­fits of exter­nal­is­ing your styles, but the main draw­back is that some­one needs to remem­ber to include that CSS file when­ever they include the script.

A sec­ond, closely related method, requires that any­one imple­ment­ing your script add your script’s styles to their own stylesheet(s). When mak­ing a rec­om­men­da­tion like this, it is best to advise the imple­menter to clearly label the group of styles you’ve sup­plied to avoid con­fu­sion when she, or some­one else on her team, edits the file later on:

  1. /​* =START Wicked­Cool Script CSS (do not remove) */
  2. .wicked {
  3.   color: red;
  4.   font: bold 4em/​2 “Comic Sans”;
  5. }
  6. .cool {
  7.   color: blue;
  8.   font: bold 4em/​2 “Comic Sans”;
  9. }
  10. /​* =END Wicked­Cool Script CSS */

This approach is less likely to cause imple­men­ta­tion issues unless some­one acci­den­tally removes the styles from the stylesheet. (It happens).

A third approach is to take the exter­nal stylesheet from the first method (above) and add it to the doc­u­ment when your script runs. To accom­plish this, you sim­ply deter­mine the direc­tory hous­ing your script, using a func­tion like FindPath()

  1. func­tion Find­Path( file­name ){
  2.   var path = false;
  3.   var scripts = doc­u­ment.getEle­ments­By­Tag­Name( ‘script’ );
  4.   for( var i=0; i<scripts .length; i++ ){
  5.     if( scripts[i].getAt­tribute( ‘src’ ) &&
  6.         scripts[i].getAt­tribute( ‘src’ ).indexOf( file­name ) != –1 ){
  7.       path = scripts[i].getAt­tribute( ‘src’ ).replace( new Reg­Exp( file­name ), );
  8.       break;
  9.     }
  10.   }
  11.   return path;
  12. }

and then add a dynamic LINK, ref­er­enc­ing the CSS file, to the HEAD of the doc­u­ment. Here’s an exam­ple of one such imple­men­ta­tion within an object literal:

  1. var Wicked­Cool = {
  2.   _​jsFile:    ‘WickedCool.js’,
  3.   _​cssFile:   ‘WickedCool.css’,
  4.   _​basePath:  false,
  5.   ini­tial­ize: func­tion(){
  6.     /​/​ deter­mine the path
  7.     this._​basePath = Find­Path( this._​jsFile );
  8.     /​/​ add the CSS file
  9.     var css = doc­u­ment.cre­ateEle­ment( ‘link’ );
  10.         css.setAt­tribute( ‘rel’, ‘stylesheet’ );
  11.         css.setAt­tribute( ‘type’, ‘text/​css’ );
  12.         css.setAt­tribute( ‘media’, ‘screen’ );
  13.         css.setAt­tribute( ‘href’, this._​basePath + this._​cssFile );
  14.     doc­u­ment.getEle­ments­By­Tag­Name( ‘head’ )[0].append­Child( css );
  15.     /​/​ do the rest of the wicked cool stuff
  16.   }
  17. };

With this in place, WickedCool.initialize() will not only trig­ger the script to work all of its wicked cool magic, but it will also dynam­i­cally add the CSS file to the page. The real ben­e­fit with this approach is that users with­out JavaScript enabled will never down­load that extra stylesheet, sav­ing them both band­width and time. It’s also easy on the imple­menter because they sim­ply need to ensure that the CSS and JavaScript files for the script reside in the same directory.

Embed­ding

The other cat­e­gory of approach utilises embed­ded stylesheets and involves plac­ing style blocks into a dynam­i­cally cre­ated STYLE ele­ment, which is, in turn, added to the HEAD of the doc­u­ment. You can do this using a script such as:

  1. func­tion add­CSS( styles ){
  2.   var el = doc­u­ment.cre­ateEle­ment( ‘style’ );
  3.       el.setAt­tribute( ‘type’, ‘text/​css’ );
  4.   if( el.styleSheet ){
  5.     el.styleSheet.css­Text = styles;
  6.   } else {
  7.     el.append­Child( doc­u­ment.cre­ate­TextN­ode( styles ) );
  8.   }
  9.   doc­u­ment.getEle­ments­By­Tag­Name( ‘head’ )[0].append­Child( el );
  10. }

This func­tion, a slight mod­i­fi­ca­tion of one devel­oped by Nicholas Zakas, allows you to sup­ply a text string of style rules for inser­tion into the head of the doc­u­ment. Imple­ment­ing this method is pretty straightforward:

  1. var Wicked­Cool = {
  2.   _​css:       ‘.wicked { color: red; font: bold 4em/2“Comic Sans”; } ’ +
  3.               ‘.cool { color: blue; font: bold 4em/​2 “Comic Sans”; }’,
  4.   ini­tial­ize: func­tion(){
  5.     /​/​ add the CSS
  6.     add­CSS( this._​css );
  7.     /​/​ do the rest of the wicked cool stuff
  8.   }
  9. };

While, tech­ni­cally, the styles are not sep­a­rated from the script itself, I don’t think any­one could argue that this approach is worse than directly manip­u­lat­ing STYLE attrib­utes on ele­ments. The ben­e­fit here is that you only need to main­tain a sin­gle file when mak­ing updates to your script; but the down­side is that the styles will not be cached, as they would if you were using an exter­nal stylesheet.

Note: this approach is far more man­age­able when work­ing with a lim­ited num­ber of styles.

Think out­side the bun

But it’s not all about tech­nique; there are other things we need to keep in mind when striv­ing to exter­nalise our styles from our scripts:

  1. #1 What you want is what you get

    When you are adding CLASS or ID attrib­utes to ele­ments, you want to avoid apply­ing unwanted styles to those ele­ments, so strive to keep their names unique. For instance, con­sider pre-​​pending the name of your func­tion or object to the CLASS or ID: “but­ton” becomes “WickedCool-​​button”. Fol­low­ing a rule like this will vir­tu­ally ensure you never expe­ri­ence a style conflict.

  2. #2 We don’t make it until you order it

    If an ele­ment already exists on a page and you want to apply some styles to it when the script runs, con­sider adding a new CLASS to the ele­ment to indi­cate it is “on” (or oth­er­wise ready to receive the script-​​related styles). This is espe­cially impor­tant if your script styles are in a sta­t­i­cally linked stylesheet, as you don’t want styles intended for the JavaScript-​​enhanced page to be applied if JavaScript is not avail­able. Here are some examples:

    At RestActi­vated
    .tabbed.tabbed-​​on
    .auto-​​submit.auto-submit.active
    .replace-​​me.replaced
  3. #3 Have it your way

    Most dynamic inter­faces require some set of core style rules to func­tion, but there are other aspects of the inter­face that should remain flex­i­ble. Sep­a­rat­ing your script-​​related styles into “core” and “skin” groups can make it really easy for you, or oth­ers, to redesign your inter­face. Obvi­ously, you’ll want to offer some sort of default skin, but you shouldn’t lock your­self or other imple­menters into that design for­ever. Pro­vid­ing doc­u­men­ta­tion of what prop­er­ties are safe to manip­u­late is also a good idea, both for your own knowl­edge and to assist oth­ers who may work with your script.

We love to see you smile

It’s not always easy to main­tain per­fect sep­a­ra­tion between your scripts and styles, but it should be your ulti­mate goal. The ben­e­fits are obvi­ous – reduced main­te­nance headaches, reduced band­width, and reduced con­flict – so we have lit­tle rea­son not to give each their own space. And, when main­tain­ing your scripts starts get­ting eas­ier, you’ll be happy. And, when you’re happy, who knows, you may burst into song…

“Keep the C-​​S-​​S on the STYLE STYLE side, and the SCRIPT [clap, clap] stays clean!”

1 back to overview

Comments on this article

  1. Written byTimid on the 6th of November

    I am inter­ested in read­ing this arti­cle, “Keep­ing the hot side hot and the cold side cold”, but only see the title? am i going mad? blind per­haps? … help?

  2. Written byGuy Leech on the 7th of November

    Timid, you’re nei­ther going blind nor mad — the arti­cles are not put online until three months after they’ve been printed. To have a read of an arti­cle before then, you have to pur­chase one of the printed ver­sions (or a PDF version).

    This issue will be avail­able online in Decem­ber, so you can either stick around for that, or grab a copy of the printed ver­sion (the PDF starts at just $3.99).

  3. Written byTimid on the 10th of November

    Thx for your response.

    I think i’ll be patient then… cheers again!

  4. Written byconrad on the 29th of December

    Check­ing this all the time… you were talk­ing about decem­ber 2008 weren’t you?

  5. Written byGuy Leech on the 29th of December

    Con­rad: Yes, that was orig­i­nally the plan. How­ever, we’ve delayed the release till the 9th of Jan­u­ary to give us a bit of time after the hol­i­days in case of unex­pected issues. So hope­fully it’ll be here in 10 days.

  6. Written byconrad on the 30th of December

    thanks for the quick response. happy hol­i­days then! best wishes, conrad

  7. Written bylazyet on the 26th of July

    Hi.
    Thank you very much for this arti­cle!
    How­ever, one draw­back (“but the down­side is that the styles will not be cached, as they would if you were using an exter­nal stylesheet.”) IMHO is wrong, as the javascript is in a file on his own, so cached as well. Still harder than some other solu­tions to spot where a dis­play bug is intro­duced though.

  8. Written byKathrin on the 29th of May

    Scroll Mag­a­zine | Keep­ing the hot side hot and the cold side cold by Aaron Gustafson” ended up being a remark­able blog, can not wait to read through alot more of ur blog posts.
    Time to squan­der a bit of time online haha. Many thanks ,
    Michell

  9. Written byLodge Discounted (Hotels_Discount) upon Twitting on the 5th of July

    I’m not that much of a inter­net reader to be hon­est but
    your sites really nice, keep it up! I’ll go ahead and book­mark your site to come back later. Cheers

  10. Written byLow cost New Orleans Hotels on the 23rd of July

    Thanks on your mar­velous post­ing! I def­i­nitely enjoyed
    read­ing it, you hap­pen to be a great author.I will ensure that I book­mark your blog and def­i­nitely
    will come back later on. I want to encour­age you
    to con­tinue your great job, have a nice afternoon!

  11. Written byLower price New Orleans Motels on the 1st of August

    Whats up very nice blog!! Guy .. Excel­lent .. Amaz­ing .
    . I’ll book­mark your site and take the feeds addi­tion­ally? I’m
    glad to find so many use­ful infor­ma­tion here within the post, we want work
    out extra tech­niques on this regard, thanks for shar­ing.
    .… .

  12. Written byTaylor on the 3rd of August

    Scroll Mag­a­zine | Keep­ing the hot side hot
    and the cold side cold by Aaron Gustafson” def­i­nitely makes me imag­ine a tiny bit extra.
    I appre­ci­ated every sin­gle part of it. Thank you ‚Rhonda

  13. Written byKristine on the 17th of August

    I actu­ally wanted to dis­cuss this par­tic­u­lar blog, “Scroll Mag­a­zine |
    Keep­ing the hot side hot and the cold side cold by Aaron Gustafson” with my best close friends
    on face­book itself. I actu­al­lyjust sim­ply wanted to dis­trib­uted ur out­stand­ing post­ing!
    With thanks, Maynard

  14. Written byliposuction is the key to looking thin on the 6th of August

    Please let me know iif you’re look­ing for a author for your blog.

    You have some really great posts and I think I would bee a
    good asset. If you eveer want to take some of the load off,
    I’d really like to write some arti­cles for your blog in exchange for
    a link back to mine. Please send me an e-​​mail if inter­ested.
    Cheers!

  15. Written byBreast Augmentation Boise on the 14th of August

    Great arti­cle about cod­ing! Love to see more like it very soon! Thanks :)

Leave a comment

Don't forget to keep track of further comments too!