External Links and new windows

Not long ago I shared some advice on handling links within your web pages. Today I want to cover linking to external sites. However, be warned, this is not a normal boagworld.com post… it contains code!

27/07/06: I have finally got around to updating the code below to reflect feedback I have received via the comments. Thanks to everybody who has contributed.

What to do with links to third party sites has always an area of debate. The accessibility purists argue that the practice of opening new windows when linking to external sites is evil and that if users wish to, they can do so themselves. However, if you have ever sat in on a usability session you quickly learn that simple things like launching a link in a new window is beyond many users. Furthermore, with so many bad sites around you cannot always rely on the back button to return the user to your site. Of course, at the end of the day these kinds of debates are redundant because if the client demands it, you will have little choice in the matter.

The golden rules of new windows

Whether you like it or not sooner or later you will have to open external sites in a new window. The trick is to ensure that this link doesn’t make your site break WAI guidelines on accessibility or invalidate your code.

Accessibility

The first problem relating to accessibility is relatively easy to solve. The guideline in question states:

Until user agents allow users to turn off spawned windows, do not cause pop-ups or other windows to appear and do not change the current window without informing the user.

The trick to complying with this checkpoint is to "clearly inform" the user that a new window is going to open. I recommend doing this in two ways. Firstly, assign the link a title tag telling the user the new window will open. Secondly, because you cannot rely on the user hovering over a link before clicking, add an icon after the link showing them something different is going to happen.

Validation

The issue of validation is a bit trickier. Normally to launch a link in a new window you use the target attribute. Unfortunately, this attribute is on the way out and will more than likely invalidate your document. Ensuring that your HTML is valid now and in the future is good practice for numerous reasons that I won’t go into here (if you want to know more about validation read my post on the subject). Sufficed to say that using the target attribute is not the answer.

Flexibility

What if your client changes his/ her mind in the future? Do you really want to be going through potentially thousands of pages altering all of the links? What you need is a solution that manages all of these links centrally so that by changing a few lines of code you can change the behaviour of all of them at once.

A neat little solution

If Jeremy Keith has taught me anything, it is that DOM scripting is great for this kind of stuff. In three easy steps, you can create external links that open in a new window while still being accessibility, valid, and flexible. Here is how:

Step 1: Semantic code

Remember we might want to change our minds about spawning a new browser window later so no target attributes or title tags talking about opening new windows. Each link to an external site will simply read as follows:

<a href="http://www.headscape.co.uk" class="">Best web design company ever!</a>

All I have done is say this links to another website with the class="", other than that it’s an ordinary link.

Step 2: Apply the JavaScript

The JavaScript function below does the following:

  1. Looks at all of the a tags on a page searching for those labelled ""
  2. Changes the class of those tags to "newWinStyle" (I’ll explain why later)
  3. Adds "(new window)" to the end of the title tag so users know it is going to spawn a new window
  4. Attaches an "onlick" event to those links so that when they are clicked it opens in a new window.

// Opens a link in a new window when class =
function doPopups() {
if (!document.getElementsByTagName) return false;
var links = document.getElementsByTagName("a");
for (var i=0; i < links.length; i++) {
if (links[i].className.match("")) {
links[i].className = links[i].className + " newWinStyle";
if (links[i].title == "") {
links[i].title = "(new window)";
}
else {
links[i].title = links[i].title + " (new window)";
}
links[i].onclick = function(e) {
if(!e)e=window.event;
if(e.shiftKey || e.ctrlKey || e.altKey) return;
window.open(this.href);
return false;
}
}
}
}

If JavaScript is disabled the link still works but opens in the same window. That is why the title tag is applied in JavaScript. If the "new window" message was added in the html it would cause confusion if JavaScript is disabled and the window spawning didn’t happen.

Step 3: The CSS

In your CSS file, you can now create a new style for "newWinStyle" and make external links look however you want. The reason you do not style "" directly is for the same reason mentioned above. You don’t want a new window icon appearing if Javascript isn’t enabled and the link wont spawn a window.

Added bonuses

This simple little approach has some great added bonuses too. Firstly, the content providers who create the links in the first place don’t need to add title tags or set the destination window for the link. Secondly, it would be easy to create an additional bit of JavaScript that allows the user to enable or disable window spawning. This gives the control back to the user where it belongs.

So what do you think? Have I missed something? Can this approach be improved? Do you believe you should never spawn a window?

  • A very useful and helpful technique which i have been using for quite some time, although i still used the externalLink class to change the css. I think i will edit my code to include what you did, where if javascript is disabled, the user doesn’t see the styling.
    One very small thing that i think could be changed, when you change the title where the title was already empty, it creates a useless space at the beginning of the tag. Just thought maybe you could do a check to see if the title is empty, if it is then don’t display a space. I know it’s a very small thing but it just makes it seem a little bit more professional.

  • I’ve been practicing a very similar method, but instead of class=”externalLink”, I use rel=”external”. I believe it’s more semantic.

  • Hi daniel,
    yeah I am aware of that one. I didnt include it in the demo because I wanted to give people a fighting chance of understanding my code. I have also been too lazy to fix it on my own site :-s

  • Hi Dennis,
    yes I guess you are right. That would be more semantic. Of course that would make the javascript code sligtly more complex but it is a good idea.

  • Ed

    Unfortunately the pages I want to talk about here seem to be offline, so I’ll link to the archive.org versions instead.)
    Just wondering whether you have considered doing what is suggested in task 3 in a Dom Scripting tutorial where the link is determined to be external “by checking that the href attribute does not contain window.location.hostname”. This can be seen in the code of the answer page for the task:
    ////////////////////////////////////////////
    // take the link’s href
    islink=as[i].href;
    // and check if it contains the current location
    if(islink.indexOf(window.location.hostname)==-1)”
    ////////////////////////////////////////////
    One thing to watch out for with doing that is, it makes it harder to test the code on an offline PC – but it means you can reduce the amount of code you produce, as you can get rid of all the “externalLink” classes.

  • To me that is a hammer to crack a walnut. Also it takes away the designers control over what is defined as an external link which sucks.

  • Ed

    Are you saying you would want to apply the “externalLink” class name to something that isn’t an external link, or that you would want to only apply the “externalLink” class to some external links and not others?
    If it is the former, then shouldn’t another name be found for the class, for semantic correctness? If it is the latter, wouldn’t that make it harder for people to get used to the web site’s interface, as they have one reaction to some external links, and another reaction to others.
    Also, could you take another look at the code you are using to make the new windows? It does odd things with Firefox’s tabs: If you hold down the Control key while clicking an external link, you get a new window pop up and the link in a new tab – the link should only appear in a new tab. If you middle-click the link, it only appears in a new tab, which is the correct behaviour.

  • Hi Ed,
    In regards to your first point: I have no idea what you are talking about!
    As for your second point: do it yourself! :)
    I was demonstrating a principle not providing reusable text. There are a lot of other people out there that do that.

  • Ed

    Ok, I’ll try again:
    you said that using the “window.location.hostname” method “takes away the designers control over what is defined as an external link”. Surley an external link is always the same thing: a link to another web site. If the class name “externalLink” was given to anything other than an external link, I don’t think it would be semantically correct. However, if some external links did pop up in a new window, and others didn’t, couldn’t that confuse some users and make the site harder to use?

  • Okay I understand now. I dont think it is fair to say that the hostname is always an indication of an external site. For example we have had many clients that run subsites within their main site with their own unique domains. These have a different domain but wouldnt in my opinion be classed semantically as an external link. Sure “technically” they are external because they have a different domain, but in the real world their not.

  • Ed

    Ok. Fair enough.

  • I’d like to add a bit to the code to make it less abtrusive.

    links[i].onclick = function(e) {
    if(!e)e=window.event;
    if(e.shiftKey || e.ctrlKey || e.altKey) return;
    window.open(this.href);
    return false;
    }

    This way people can still open a link in a new tab etc. if the really want to.

  • Thanks for that Gerben, very useful
    Yhink I will use that in my code, if it’s not a problem?

  • no problem. I wished more people would write userfriendly/usercentered code.

  • Here is an updated version of the code including some feedback I have received:
    function doPopups() {
    if (!document.getElementsByTagName) return false;
    var links = document.getElementsByTagName(“a”);
    for (var i=0; i

  • one could even use
    links[i].target = ‘_new’;
    instead of links[i].onclick = … if you don’t want to specify any other window-properties for the popup.
    nice idea to add ‘(new window)’ to the title-attr.

  • Okay, as much as I like this method–and I’ve even been working it into my own blog–I have not been able to figure out a way to exclude linked images from having the same little externalLink icon as the externally linked text. This is very annoying. BTW, there’s also a problem with text hyperlinks that span two or more lines on the page.
    Has anyone figured out a workaround for this yet? I’d really hate to have to create a separate class handler for images (like externalLinkImg) as well as the corresponding JavaScript function to process it without the newWinStyle.

  • Ed

    ptvGuy, I guess you could add a bit of javascript to say “if the doesn’t contain an image, don’t add the rest of the code”
    something to do with child nodes, I would think

  • Ed

    “if the doesn’t contain an image, don’t add the rest of the code”
    should be
    “if the link doesn’t contain an image, don’t add the rest of the code”

  • Ed

    eeeek – I mean
    “if the link contains an image, don’t add the rest of the code”
    I really should slow down!

  • The way the function is currently written, it uses “getElementsByTagName” to pull out properties of the anchor tag itself. That means that it will process elements of the anchor tag like “title,” “href,” and “class.” It completely ignores whatever’s between the opening and closing anchor tags as to whether it’s text an image or nothing at all. That means that I could potentially apply the externalLink class to an empty named anchor and have it simply make the new window icon appear in a spot with no related hyperlink, have a title text that says “(new window)”, and actually open a new window with nothing in it.
    I’d really hate to add any overhead to what is already a distractingly slow-running script. That’s not a complaint, by the way. It’s just that the JavaScript can’t process the anchor tags until after the page loads. That means that users can actually see the page being changed after it already appears to be loaded. One could even make the argument that this could be confusing to users with cognitive disabilities (or those with little or no computer experience), and I’m not exactly certain how this might affect people using screen readers who may try to access the various hyperlinks before the page has finished processing.
    I realize that we can’t make everything perfect for everyone or cover every potential situation. Most of us (web developers) don’t get paid for or have the time available to do many of things we’d like to do for accessibility. So, for ease of implementation and maintenance, this is the best method I’ve seen yet. It just needs some tweaking and refinement.
    I’ve tried using CSS in different ways to isolate anchor tags with images and prevent the icon from appearing, but it hasn’t worked:
    a.newWinStyle img {
    background-image: none;
    padding: 0;
    }
    img a.newWinStyle {
    background-image: none;
    padding: 0;
    }
    I hope that we can get some discussion going on this subject again and possibly work out this annoying problem along with what to do about multiline text hyperlinks.

  • James Bellew

    Hi Paul
    I tried using the re-do of your javascript that you added later on – but it’s got a coding error. I guess it was a cut and paste issue…
    function doPopups() {
    if (!document.getElementsByTagName) return false;
    var links = document.getElementsByTagName(“a”);
    for (var i=0; i
    ** it was missing this bit ***
    < links.length; i++) {
    ** end of extra code ***
    if (links[i].className.match(“externalLink”)) {
    links[i].className = links[i].className + ” newWinStyle”;
    if (links[i].title == “”) {
    links[i].title = “(new window)”;
    }
    else {
    links[i].title = links[i].title + ” (new window)”;
    }
    links[i].onclick = function(e) {
    if(!e)e=window.event;
    if(e.shiftKey || e.ctrlKey || e.altKey) return;
    window.open(this.href);
    return false;
    }
    }
    }
    }
    See ya.

  • nxtyear

    ok i’m relatively new so i might need help here,
    which class do i style in CSS?
    i tried styling the .newWinStyle but it doesn’t seem to work.
    could someone please explain what this line is doing?
    links[i].className = links[i].className + ” newWinStyle”;

  • nxtyear

    ok.. just found out the whole script isn’t working, not just the style.
    none of the links with the class “externalLink” is opening it in a new window…
    is there any reason why it might be that i’m the only one having trouble getting it working :S?
    mind you i’m including an external js file into a phpinclude. which in turn is applied to the page with the links.. would that have anything to do with this?

  • nxtyear:
    Without a link to your site, no one can look at what’s going wrong. I would suggest opening the page in your favorite browser and then viewing the source code to see if the JavaScript coding is even getting to your page correctly from the PHP include. Then look through your external link anchors in that source code to see if they’re properly coded with the the class=”externalLink” attribute. Doublecheck the class designation as well to make sure that it’s all lowercase except the capital “L” since JavaScript is case-sensitive.
    BTW, I apologize if that information is just painfully obvious to you, but I have no way of knowing your coding level, and I wanted offer as much input as I could. I hope that helps.

  • nxtyear

    actually, i figured out the problem, it seems that browsers don’t support “getElementsByTagName” yet. i’ve no idea how paul got it working though :S

  • I would highly appreciate if someone give me a clue on icons in the end of multiline links.

  • would highly appreciate if someone give me a clue on icons in the end of multiline links.

  • nice site. thanks.

Boagworks

Boagworld