Lately I’ve been working on a personal project of mine, redesigning and revitilizing my website about Bipolar Disorder. It’s still deeply entrenched in the redesign and I’m not even done with the site templates yet, but I was anxious to get some content rolling out quickly so I went ahead with it anyway.
Some elements of the design, however, relied on dynamic scripting to style appropriately. The key thing here, however, is that I wanted to avoid accessing or manipulating style elements from within the JavaScript script. In other words, I wanted to ensure that all my style rules, the visual declarations for the presentation of these links, would be kept in the site’s CSS.
There were several reasons for this:
- To keep presentation clearly separated from behavior and structure.
- To keep the JavaScript unobtrusive and portable.
- To ensure that both aspects, presentation and behavior could be easily updated or altered in the future.
- To allow for various styling without touching the script.
Typically, a JavaScript script with a line similar to elem.style.property = 'value'; is used to create so-called “dynamic styles.” Unfortunately, this would not do for me.
So I fiddled and found that the best way to go about this was to simply tag links that I wanted to style by adding a word to their class name and then write styles for the selected elements inside my stylesheets. In effect, links in my page will be transformed from <a href="http://some.other.site/"></a> to <a class="external" href=”http://some.other.site/”></a> So I sat down and wrote this little plug-and-play JavaScript to tag the links I wanted. Let’s go over it line-by-line. (If you’re antsy, here’s the whole script.)
First, we define a function named catchExternalLinks. Then we set a variable, extClassName, to hold the class name we’re going to add to the links. While not strictly necessary to hold in a variable, it does make for easy editing later. Don’t like the word “external” for a class name? Change it to something else.
function catchExternalLinks()
{
var extClassName = 'external';
Next, we do some object detection. This is to ensure that the browser can handle what we’re going to ask of it. Browsers that can’t handle it won’t try to, which is good because it means visitors won’t see an error when they visit the site. They just won’t see the dynamic styling.
if (document.links && document.getElementById) {
Now that we know we’re talking only to browsers which can handle our instructions, we define a variable, h (for host), which will store the beginning of the web address that we’re at. On www.maymay.net, h now contains the string http://www.maymay.net.
var h = window.location.protocol + '//' + window.location.host;
Next, we need to gather all the links in our page. We assign the links array to the variable l.
var l = document.links;
We need to work with each link separately, so we loop through the links…
for (var i = 0; i < l.length; i++) {
…and assign the value of the href property to the target variable after turning the string toLowerCase text.
var target = l[i].href.toLowerCase();
We only want to work with real links, so first we make sure we’re not dealing with javascript: directives.
if (target.substr(0, 11) != 'javascript:') {
Then we search the target string of the link for the h string. If we don’t find it…
if (target.substr(0, h.length).indexOf(h) == -1) {
…then this link is an external link so we tag it as such by adding the extClassName to its className preceded by a space. We do this instead of using setAttribute() because this way we can keep any pre-existing values for the class attribute already in the link. The key here is to know that className accesses the class attribute of an element.
l[i].className += ' ' + extClassName;}
Finally, after closing all our blocks properly, we set the catchExternalLinks function to execute onload.
}
}
}
}
window.onload = catchExternalLinks;
Of course, as per the requirements for this script being as unobtrusive as possible, it won’t do anything to the style properties of the link. All it did was add a class value, so we’ll need to declare our styles in our stylesheet. In my CSS page, I write the following to display a little icon for these links.
a.external {
padding-right: 15px;
background: transparent url(extlink.gif) center right no-repeat;
}
The styling possibilities are really rather endless now. Since I can instantly identify external links via the class external, I can also write context-specific styles. For instance, I can limit my styles to only one part of the page with a selector such as
#main a.external { ... }
or I could write different styles for external links for the sidebar and a comment on my entry with
#sidebar a.external { ... }
.blogComment a.external { ... }
or any other styling I see fit. In addition, from the script, it’s very easy to test for links that meet a specific criteria, say, Google definition searches, simply by adding another if clause inside the main loop. Here’s a version that does just that.
All together, it goes like this:
function catchExternalLinks()
{
var extClassName = 'external'; // the class to set for external links
var defClassName = 'defSearch'; // the class to set for definition searches
if (document.links && document.getElementById)
{
var h = window.location.protocol + '//' + window.location.host;
var l = document.links;
for (var i = 0; i < l.length; i++)
{
var target = l[i].href.toLowerCase();
if (target.substr(0, 11) != 'javascript:') // only work on links that aren't JavaScript directives
{
// tag external links
if (target.substr(0, h.length).indexOf(h) == -1)
{
l[i].className += ' ' + extClassName;
}
// tag Google definition search links
var anchor = l[i].childNodes[0].nodeValue; // anchor now contains the anchor text of the link
var s = '?q=define:' + anchor;
if (target.substr(0, target.length).indexOf(s) != -1) // use != to ensure that the string (var s) EXISTS in target
{
l[i].className += ' ' + defClassName;
l[i].title = 'Definitions for ' + anchor + ' on the Web.'; // for the link tooltip
}
}
}
}
}
window.onload = catchExternalLinks;
Feel free to steal this snippet. Just remember to write your styles in a stylesheet that you connect to your page, or the script won’t have any noticeable effect. Of course, that’s the whole point. Enjoy! ;)