New-Window Links in a Standards-Compliant World Article
Much to the chagrin of Web designers everywhere, the HTML 4.0 Strict and XHTML 1.0 Strict recommendations of the W3C no longer include the target
attribute of the <a>
tag. The Transitional versions of the specifications still include it, but by definition, these specs are on the way out.
Whatever your personal feelings on the practice, the most common application for this attribute — opening a link in a new browser window with target="_blank"
— is still useful on today’s Internet. So if the standards say we shouldn’t use it, how should we go about creating new-window links, while following the latest Web standards?
Idealism Applied
The Web standards are written with a lot of ideals in mind. In many cases, established practices go by the wayside in favour of “the right thing to do”. One of the ideals that is expressed by the removal of the target
attribute from the Strict standards is that (X)HTML should only be concerned with the information that’s displayed within a browser window.
Consequently, as soon as we start talking about opening new browser windows, the idealistic notion is that we have exceeded the responsibilities of (X)HTML and entered the world of client-side scripting (i.e. JavaScript).
But before we dive into the JavaScript code necessary to open a link in a new browser window, we still have a fundamental problem to solve. We still need a way to mark links that should be opened in a new window, and if we can’t use the target
attribute to do it, we need to find some other way — a way that fits with the ideals behind the latest (X)HTML standards.
A New Relationship
The HTML 4.0 specification took away the target
attribute, but it added another attribute: rel
. This attribute is intended to specify the relationship between the document that contains the link, and the target of the link. The specification defines a bunch of standard values for this attribute (e.g. next
, previous
, chapter
, section
), most of which have to do with relationships between small sections of a larger document. However, the spec leaves the developer free to use nonstandard values for site-specific purposes.
Here at SitePoint, we have adopted a custom value for the rel
attribute to mark links leading to other Websites. These are the very same links that we want to open in a new browser window. For these links, we set the rel
attribute to external
.
Before:
<a href="document.html" target="_blank">external link</a>
After:
<a href="document.html" rel="external">external link</a>
So, now that we have our new-window links marked up in a standards-compliant way, we need to write the JavaScript that will cause them to actually open in a new window.
Deconstructing the Script
The job of our script, which will be run once the document is loaded, will be to find all the hyperlinks in the document and modify those that have our special (but standards-compliant!) rel="external"
attribute, so that they open in a new window.
Sound daunting? Don’t worry — the code’s not too bad. The first step is to make sure the browser is up to the task:
if (!document.getElementsByTagName) return;
getElementsByTagName
is a handy method of the Document Object Model 1.0 (DOM1) standard supported by modern browsers. Since a few of the older browsers that are still hanging around, such as Netscape 4 and Internet Explorer 4, don’t support DOM1, we need to weed them out by checking for the presence of this function. On those browsers, we simply return and let external links open in the same browser window — no great loss, in most cases.
Next, we use the getElementsByTagName
method to get a list of all the <a>
tags in the document:
var anchors = document.getElementsByTagName("a");
anchors
will contain a JavaScript array after the method does its job. Each element in the array will represent an <a>
tag in the document.
Now we need to go through all of the <a>
tags we just found and modify those that represent new-window links. You can use a JavaScript for
loop to work on each of the tags in turn:
for (var i=0; i < anchors.length; i++) {
var anchor = anchors[i];
For each element in the anchors
array, we create a variable inside the loop called anchor
to isolate the tag with which we are currently concerned.
Now we need to check if anchor
represents a new-window link. As I’m sure you know, the <a>
tag isn’t just used to create hyperlinks. With a name
attribute, you can create a target for links that go to a particular location in the page. Only <a>
tags with an href
attribute qualify as hyperlinks. Our code must therefore check that anchor
has an href
attribute as well as a rel
attribute that is set to external
.
if (anchor.getAttribute("href") &&
anchor.getAttribute("rel") == "external")
Now that we’ve confirmed that we’re dealing with a new-window link, we can set its target
attribute to "_blank"
:
anchor.target = "_blank";
And that should do it! Read on for the complete code, and for a few more words on why this solution is acceptable…
A Fine Line
As a bit of a perfectionist, my first impulse when I learned of this solution was to ask, “Is there really a difference?” And yes, I often talk to myself while doing research.
I mean, if the target
attribute of the <a>
tag is being phased out, does it really make a difference whether we’re setting it with JavaScript instead of HTML? Sure, the page will validate against the HTML 4.0 Strict and XHTML 1.0 Strict Document Type Definitions, but aren’t we technically cheating?
The answer is no. The Document Object Model (DOM), which governs the document objects and attributes that are available to JavaScript code, is a totally separate standard from (X)HTML. Also consider that the DOM 2.0 standard that was published in January 2003 (well after XHTML 1.0, let alone HTML 4.0) still includes this attribute. It seems clear that while this attribute is slated to be phased out of (X)HTML, it will be available to JavaScript through the DOM for the foreseeable future.
A number of other standards-compliant new-window link scripts out there propose using window.open()
to load the document in a new window. While this approach generally works well on the surface, its downfall is that most browsers do not correctly report the referring URL in the request for the new page, which can be a serious issue, especially in inter-site links.
The Complete Script
As promised, here is the complete script. Notice the last line, which assigns the externalLinks
function to the window’s onload
event handler. This triggers the function when the document has finished loading.
function externalLinks() {
if (!document.getElementsByTagName) return;
var anchors = document.getElementsByTagName("a");
for (var i=0; i<anchors.length; i++) {
var anchor = anchors[i];
if (anchor.getAttribute("href") &&
anchor.getAttribute("rel") == "external")
anchor.target = "_blank";
}
}
window.onload = externalLinks;
As this is the kind of script you’ll want to deploy across your entire site, you should copy this code into a separate file (e.g. external.js
), and then load it in every page on your site with the following code, which should appear in the <head>
tag of each document:
<script type="text/javascript" src="/external.js">
</script>
Problem solved!