Using <base href/> with AnchorsBy Roger Keays, 26 June 2007 |
Using <base href/> with AnchorsA <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:
- Your site can be easily ported to a new location; and
- 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:
- When new pages are created they don't yet have a URL, and
- 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 Keays is an artist, an engineer, and a student of life. He has no fixed address and has left footprints on 40-something different countries around the world. Roger is addicted to surfing. His other interests are music, psychology, languages, the proper use of semicolons, and finding good food.
|
<a href="javascript:;" onclick="document.location.hash='anchor';">Anchor</a>
This worked great for me.
THANK YOU.
Thank you, Roger, for your solution.
I successfully used it in documents, generated using XSLT, in AndStatus application. See https://github.com/andstatus/andstatus/blob/master/app/res/raw/fb2_2_html.xsl
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 + "#");
}
Andrius's code works perfectly! Thanks!
@Dimitris
THANK YOU SO MUCH FOR THE NICE CODE. IT WORKS BEAUTIFULLY FOR ME.
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);
});
});
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);
});
});
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);
}
);
“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.
Brilliant !! Thanks very much. I've used it today !
Here the solution if using jQuery
$("a[href^='\#']").click(function(e){
e.preventDefault();
document.location.hash=this.href.substr(this.href.indexOf('#')+1);
})
tks a lot.
here's another solution:
http://howtobuildawebsite.blogspot.com/2007/11/base-href-and-named-anchors.html
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.
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);
}
}
}
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.
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.
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.
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