Patterns in Software

Using <base href/> with Anchors

By , 26 June 2007

Using <base href/> with Anchors

A <base href="homepage-url"/> tag in the header of the pages in your site is enormously convient for building sites which can be moved from one domain or location to another. Unfortunately, there is one downside - it breaks anchor links. In this blog I explain the whole problem with the base tag and show you how you get around the problem with broken anchor links.

The purpose of the <base/> tag is to specify the base location for resolving relative urls. It was only ever meant to be used for viewing a page where the document root is not available (for example, from an email) and should technically point to the actual document location, rather than the homepage. However, there are two significant advantages to the latter:

  1. Your site can be easily ported to a new location; and
  2. Your web applications can be built without any reference to the location they are installed.

Any HTML purist and they'll tell you that using <base href="homepage-url"/> to artificially rewrite all your urls relative to your homepage or application context is abusing the intended use of the tag. Well, okay, so that's not what it was designed for, but I'm fairly certain HTML wasn't design to build applications like Google Maps either, but people did it anyway.

Using <base href/> with Anchors

The problem

The Achille's Heel of the base href tag is that anchor links will all resolve to the homepage unless you include the relative path of the document also. For example, if the base href was http://www.example.com, notice how the following urls are resolved: 

  Relative URL Absolute URL
Broken: #anchor http://www.example.com/app#anchor
Corrected: page#anchor http://www.example.com/app/page#anchor

This doesn't cause a problem if you are happy to manually include the page location in each anchor link. For our CMS however, we wanted the editor to do this work for us and there are two problems with making this transparent to the user: 

  1. When new pages are created they don't yet have a URL, and
  2. If the user changes the url of a page, the links need to be updated also.

The solution

To solve this problem we turned to our temperamental friend, Javascript. Javascript can be used to fetch the absolute location of a document, and then just add the anchor on the end. All that we needed was to program the editor to insert anchor links to look like this:

<a href="javascript:;" onclick="document.location.hash='anchor';">Anchor</a>

These links downgrade gracefully when javascript is not available and simply do nothing when they are clicked. 

View a demonstration of the javascript anchors.

About Roger Keays

Roger is an active member of the JSF 2 Expert Group and is happy to be a contributor to the Java Community. He has been writing software since the age of 8 and his other interests include languages, science, travel and running.

Comment posted by: wally, 6 years ago

This doesn't work.

First of all you don't close the onclick, secondly this is not SEO-friendly. I solved it like this.

 <a href="page.html#anchor" onclick="document.location.hash=this.href.split('#')[1];return false;">Go to anchor.</a>

This way googlebots and suchlikes can index your page and still be able to follow your links. Because googlebots do (presumably) not have javascript enabled and they will not be able to follow your links.

Best regards,
wally

Comment posted by: , 6 years ago

Hi Wally,

Thanks for the comments. I fixed up that onclick attribute. As for search engines not following the links, I'm not sure I would be too worried seeing as this method only works for anchors on the current page. Presumably if a search engine bot could find the current page it wouldn't need to be told which to anchor regions to index, as it would index the whole page by default.

Comment posted by: wally, 6 years ago

 Hi Roger,

Okay, the links may not be of importance to the search engines but I find it better to know where I'm heading i.e. being able to se the #anchor. Also, you cannot open the links in a new window/tab.

Comment posted by: Greg Pool, 6 years ago

Good solution, but the best is to resolve to the actual file and not the document root. Then you wouldn't have to use JavaScript.

Here's the W3C on Links in HTML Documents. The key is "The path information specified by the BASE element only affects URIs in the document where the element appears."

It's even better if you can create the BASE HREF dynamically, like in PHP or XSL. I did this with the latter, and it meant I got the benefit of resolving URLs on a server with lots of virtuals in addition to making my anchors still work.

Comment posted by: Matt Montag, 5 years ago

Here is my approach to the problem - insert this script before your close body tag and it will rewrite all the in-page anchor tags.

/*
Rewrite #anchor links for pages with BASE HREF
*/
var anchors = document.getElementsByTagName("a");
var basehref = document.getElementsByTagName("base")[0].href;
var url = window.location.href;
if(url.indexOf("#") > 0) url = url.substr(0, url.indexOf("#")); //strip hash
if(basehref) {
 for(var i = 0; i < anchors.length; i++) {
  var anchor = anchors[i];
  poundPos = anchor.href.indexOf("/#");
  if (poundPos > 0) {
   anchor.href = url + anchor.href.substr(poundPos + 1);
  }
 }
}

Comment posted by: , 5 years ago

Hey Matt, nice solution. I guess it won't make any sense to search engines, but they should just see those anchors as links to the base href page so no big deal.

Comment posted by: Marcelo Oliveira, 5 years ago

tks a lot.

here's another solution:
http://howtobuildawebsite.blogspot.com/2007/11/base-href-and-named-anchors.html

Comment posted by: Dmitris, 5 years ago

Here the solution if using jQuery

$("a[href^='\#']").click(function(e){
  e.preventDefault();
  document.location.hash=this.href.substr(this.href.indexOf('#')+1);
})

Comment posted by: Ash, 4 years ago

 Brilliant !! Thanks very much. I've used it today !


Comment posted by: Scytale, 3 years ago

“These links downgrade gracefully when javascript is not available and simply do nothing when they are clicked.” – You might want to check your definition of “graceful”. The only real solution is to get rid of the BASE tag. As a rule of thumb: If you’re using BASE in a HTML document which is to be displayed in a browser and transferred via HTTP, you’re doing it wrong.

Comment posted by: tjungcl, 2 years ago

another jquery based solution similar to matts, but a bit more robust:

$("a[href^='\#'][href!='\#']").each(
    function (i,e){
        var href = $(e).attr("href");
        //does element with id = hash or link name = hash exist?
        if ($(href).length || $("a[name='" + href.substring(1) + "']").length)
            $(e).attr("href", $(location).attr("href").split("#",1)[0] + href);
    }
);

Comment posted by: Andrius, 2 years ago

I have tuned jquery script to replace links in document. In this case even opening links in new window is not a problem:

$().ready(function() {
$("a[href^='\#']").each(function(){
  this.href=location.href.split("#")[0]+'#'+this.href.substr(this.href.indexOf('#')+1);
});
});

Comment posted by: Andrius, 2 years ago

I have tuned jquery script to replace links in document. In this case even opening links in new window is not a problem:

$().ready(function() {
$("a[href^='\#']").each(function(){
  this.href=location.href.split("#")[0]+'#'+this.href.substr(this.href.indexOf('#')+1);
});
});

Comment posted by: Joshi Thomas, 2 years ago

 @Dimitris

THANK YOU SO MUCH FOR THE NICE CODE. IT WORKS BEAUTIFULLY FOR ME.

Comment posted by: Aalaap Ghag, last year

Andrius's code works perfectly! Thanks!

Comment posted by: andreawilliamss, last year
Comment posted by: joannacrupa, last year
Comment posted by: andreestock, last year
Comment posted by: andreestock, last year
Comment posted by: provwechslichard, last year
Comment posted by: jekeectaffist, last year
Comment posted by: hhattiaash, last year
Comment posted by: MichaelDenwon, last year
Comment posted by: hhattiaash, last year
Comment posted by: hoojanelo, last year
Comment posted by: hojanelo, last year
Comment posted by: hojjanelo, last year
Comment posted by: londonhallo, last year
Comment posted by: , last year

After revisiting this problem, I've opted to use a server side transform to preprocess the anchor links. It's simple and works for browsers and search engines.

    public String transform(String url, String html) {
        return html.replaceAll("href=\"#", "href=\"" + url + "#");
    }

Add a comment

Please visit http://www.NinthAvenue.com.au/blog/using-base-href-with-anchors to add your comments.

Join The Mailing List

Subscribe to our mailing list for the latest news and announcements.

Follow Ninth Avenue

Website Updates