The obsession
While I am busy changing diapers, planting trees, and replacing brick moulding, several other web developers are spending their remaining summer days sipping on cocktails or one-upping each other with their respective takes on ampersands on the web. Don't get me wrong - I do love the fact that I have been lucky enough to recently become a homeowner and a father and am amazed at how well the my body has adjusted to function on a couple interrupted hours of sleep - but I feel like I'm missing out on the party.
Through the eye crusties and clouds of baby powder, I've managed to gather the following:
- Meagan Fisher self-diagnosed her ampersand fever, and spewed a desktop wallpaper containing some of the more interesting ampersands.
- Dan Cederholm revisited his presentation on using CSS to add some salt and pepper to ampersands by wrapping them in <span class="amp"> tags which the browser then styles using corresponding CSS. Apparently he also bought some sweet ampersand swag.
- Jeremy Keith replied to Dan's post that it is arguably semantically more appropriate to use the <abbr> element since the ampersand is used as an abbreviation of the word "and."
- Patrick Haney decided that Dan and Jeremy had good ideas, but thought it was a pain to hand wrap each ampersand with care. It's better to use JavaScript via the jQuery framework to automatically find and style all appropriate ampersands. This is similar to the way Google Prettify stylizes source code on this blog. As an added bonus, you don't have to manually find and wrap ampersands in old code and blog archives to give them the special wrapping needed!
Patrick has the right idea. But, I'm getting up on my little soapbox to declare my professional opinion that the
Dojo Toolkit's dojo.query is the better choice for some users for several (possibly biased) reasons.
- The minimized Dojo resources needed to query the DOM is lighter than minimized jQuery. At the time of this writing, YSlow shows empty-cache requests for Dojo coming over the AOL CDN at 39K and jQuery via Amazon S3 at 56K.
- When querying the DOM, Dojo consistently comes in first during benchmark tests on FireFox 2.x and FireFox 3.x (here Dojo is twice as fast!). The results are a wash on Google Chrome 0.2 ans Safari 3.x because they are both blazingly fast. Unfortunately Dojo lags a bit behind jQuery in IE 6.x and IE 7.x, and the tests are butchered in IE 8 beta, but I find the majority of my users are not using IE.
- Dojo's syntax is a bit more legible.
- I was a technical reviewer of Pragmatic's Mastering Dojo book and use Dojo at my day job so you might say I am an advocate.
- There is more than one way to skin a cat, and this might help someone who has an interest in the Dojo Toolkit.
If this serves no other purpose than to provide someone an option of using an alternate framework to jQuery, then my job is done.
Jumping right in
All the great groundwork is already laid out in Patrick's 2,000 word post, so I'll spare you the details and jump right into the meat and potatoes (or potatoes and potatoes for my vegetarian audience). Check out his post because he does a better job of explaining the background and regular expression string replacement.
In summary his jQuery code
$(document).ready(function() {
$("*:contains('&')", document.body)
.contents()
.each(
function() {
if( this.nodeType == 3 ) {
$(this)
.replaceWith( this
.nodeValue
.replace( /&/g, "<abbr title='and' class='amp'>&</abbr>" )
);
}
}
);
});
makes all ampersands in the html body DOM node turn into
<abbr title='and' class='amp'>&</abbr>
and the CSS
abbr.amp {
font-family: Baskerville, Palatino, Constantia,
"Book Antiqua", "URW Palladio L", serif;
font-style: italic;
}
gives them a little bit of style.
In Dojo, the CSS doesn't change, but the JavaScript becomes:
dojo.addOnLoad(function() {
dojo.forEach(
dojo.query("body *:contains(&)"),
function(node) {
node.innerHTML
= node.innerHTML.replace(/&/g,"<abbr title='and' class='amp'>&</abbr>");
}
)
});
Here you can see why I prefer Dojo's syntax over jQuery. The code reads a bit more like English pseudocode. Simply:
Wait for the page to finish loading loading. For each DOM node we're looking for, perform a certain string replacement.
If you're still scratching your head, don't worry. Here are complete working examples.
Comparing the Dojo and jQuery examples
- For all intents and purposes, dojo.addOnLoad function is the same as jQuery's $(document).ready function. Both are used to specify JavaScript to run after the page is loaded.
- dojo.forEach function takes two parameters - an array and a function - and performs the function for each element of the array. jQuery's .each is an Array method that iterates over each element and performs the function passed to it on the current element.
- dojo.query can query the DOM just like CSS selectors. So we can specify that we only want to look at the body right in our selector. This is more straightforward than jQuery's $, which requires a second parameter to specify a context node, if desired. (Can someone tell me why the selector in the Dojo example doesn't work in jQuery?)
- dojo.forEach passes the current element to the function (a DOM node in this case). jQuery uses the "this" JavaScript object to refer to the current element, which can be pretty confusing and lead to some dicey debugging.
- I'm not sure why jQuery example diverges futher from the native DOM language by introducing .replaceWith and .nodeValue. I think these are pretty worthless "helpers" that only add to confusion. Getting the DOM node's value by the standard .innerHTML is suitable and allows for more legibile code for anyone familiar with JavaScript and DOM.
- Using .innerHTML, we have to replace "&" instead of "&" with the markup because we're looking at exactly that, the inner HTML of the node (and because you are using the proper XHTML character code, right?). Counterintuitively, jQuery's nodeObject.nodeValue returns the value as it is rendered by the browser, so the regular expression in that example only looks for "&". How confusing, because nodeObject.replaceWith expects markup!
- This dojo.query example comes in at 2/3 the character count of jQuery!
- dojo.query performs better than jQuery on FireFox, and about the same on Safari and Chrome. jQuery performs better than Dojo with any significance in IE only.
Making bling ($)
I prefer Dojo's legible syntax over jQuery's, but I know many like the abbreviated bling function to save some typing. If you can't do without the bling, you can make your own in Dojo. Check out Neil Roberts's article over at the DojoCampus to find out how you can use the $ shortcut with Dojo to query the DOM and $.ready(...) in place of dojo.addOnLoad(...). Sick!
Then your blinged out Dojo becomes
$.ready(function() {
dojo.forEach(
$("body *:contains(&)"),
function(node) {
node.innerHTML
= node.innerHTML.replace(/&/g,"<abbr title='and' class='amp'>&</abbr>");
}
)
});
Wrapping up
When I started at noon yesterday I thought this was going to be a quick post... Alas, I have managed to make a long story longer and bore you with 1,200+ words of my own. Meagan and Dan probably never thought that their interest in an aesthetically pleasing character would devolve into a nerdy discussion about performance and approach, but that's where my Computer Engineering background comes into play.
Anyway, all of the mentioned players brought a lot of good ideas to the table. I've added what I think are reasonable reasons why someone might want to use Dojo over jQuery in similar cases. Those of you who know my know I have a "right tool for the job" mentality. Furthermore, the right tool for one person is not necessarily the right tool for another.
Choose wisely my friends. Choose wisely.