The Web community is going crazy about SEO-friendly URLs like http://somesite.com/products/network/router/. Well, it looks much better than a script URL http://somesite.com/products.php?c=network&p=router which may actually serve the page behind the scenes. There are a lot of good articles on how to implement SEO-friendly URLs, for example this one or my own post. But they do not warn the reader about one usual problem: once you have updated your site to handle virtual paths you will probably get a bad surprise:
CSS, image and internal page links are totally broken!
Why? Because those links are usually relative to the page location. The browser has no idea about virtual folders and tries to get files from locations relative to the page URL context. For example, if there is a usual CSS link in the page header:
<link rel="stylesheet" href="style.css" type="text/css" media="screen" />
Then the browser will try to download non-existing file http://somesite.com/products/network/router/style.css and fail silently. No CSS style will be applied.
It’s incredible how many words were spoken about SEO-friendly URLs with almost no word about this relative link problem.
So, what you have to do? Don’t worry, there are multiple solutions available and I’ll try to explain them all.
Use <base> Tag in HTML Header
This is the most easy and reliable solution available. Absolutely the winner!
Just add a base tag with proper absolute location to head section of your page prior to any CSS link and the page will work again like a charm:
<head> <base href="http://somesite.com/" /> <link rel="stylesheet" href="style.css" type="text/css" media="screen" /> </head>
Well done! That’s all you really need.
The href parameter of base tag specifies the base path for relative links instead of a default page path.
Surprisingly, so useful tag is not well mentioned in manuals. But it is well supported by browsers and search engine bots so there is no need to worry about it. According to blooberry.com it is supported from IE 1.0, Opera 2.1 and Safari 1.0. Even Internet Explorer 5.0 supports it, LOL.
Base tag also works for relative URLs in CSS.
But you still need to take care about JavaScript code like window.open(). It’s recommended to use absolute URLs with JavaScript.
If there is any reason base tag can’t be used, please let me know in comments.
To avoid hard-coding absolute base path in every script you can set it as a constant. Alternatively, you can get it dynamically:
$baseUrl = dirname($_SERVER['PHP_SELF']).'/';
Other Solutions You May Want to Try
In case the solution with base tag is not an option, you can try one of the following solutions.
URLs relative to the site root
URLs beginning with a slash like /images/header.gif are considered relative to the site root folder. For example, if this link appears on any page of somesite.com it will always point to http://somesite.com/images/header.gif regardless of page URI.
This option is not acceptable if you need an ability to install your script in various locations of web server directory tree. For example, it will not work in your development environment if the URL of sandbox site copy is something like http://localhost/dev/somesite.com/.
But you can set up a virtual host in your development environment to use links relative to the site root. Thanks to Dan Lidral-Porter for the suggestion in comments to the article.
Absolutize URLs on-fly
With absolute site URL in hand you can convert relative links to absolute ones on page generation.
You can do this by adding absolute part when printing relative links:
<link rel="stylesheet" href="<?php echo $baseUrl; ?>style.css" type="text/css" media="screen" />";
Alternatively, you can do this by parsing HTML code and replacing relative links just before page output to the client. This is useful when you actually display HTML content loaded from another web site.
Have all shared stuff on an external domain
Since your CSS and JS may contain hardcoded URLs too and any change in the domain will affect them, you can move shared stuff to external cookieless domain and use absolute links to it.
(Thanks to Berny Cantos for the suggestion in comments to this article.)
Add rewrite rules for images, CSS, etc
Absolutely not recommended solution. Even while it works it results in terrible and badly extendable rewrite code.
Conclusion
Development of modern web sites always involves implementation of rewriting for SEO-friendly URLs. Keep in mind that you also need to solve relative link problem. Usage of base tag is the most recommended solution.
I had no idea a forward slash before a relative link would still point to the root. I thought it was still relative to wherever you were at. Thanks for showing me something new!
Good article! It makes me think about this.
I would like to see more sites using the base tag. It’s a nice HTML feature, unfortunately underused. Is it understood correctly under all browsers (IE and associates)? I don’t know.
Also, I don’t think the use of absolute URLs is the best solution, since your CSS and JS may contain hardcoded urls too and any change in the domain will affect them.
For static files, like CSS or JS, I’d suggest using absolute urls with an external cookieless domain.
Thanks!
Berny, thanks for commenting!
According to http://www.blooberry.com/indexdot/html/tagpages/b/base.htm BASE tag is supported from Internet Explorer 1.0, Opera 2.1 and Safari 1.0.
I’ll add your suggestion about external domain to the article.
By the way, BASE tag works for relative URLs in CSS.
I always use URLs relative to my site root. There’s an easy solution to the problem you cited above for this. On my development sandbox, I just create a new virtual host in the apache httpd.conf:
ServerName somesite.dev
DovumentRoot /path/to/dev/sandbox
Then, add a new entry to your hosts file:
127.0.0.1 somesite.dev
After this, you can go to somesite.dev in your browser, and all the relative-to-root URLs will resolve as expected.
Dan, thanks for commenting and noticing me about the solution!
Though I don’t like to modify environment config for every project, I’ll add your suggestion to the post.
Thanks Anton this is great. and it’s one of those anoying oversights people run in to when setting up there $_Gets.
Having had some trouble with my htacess and my $_get being compressed down to the most optimal for several tasks, then having spent several hours looking for solutions, I gotta say that this page is a real life saver.
At first I thought that the mod rewite engine had a bug regarding rewritten rules for non existent / pages, all along I was missing a / on my css and other media in the header, however I can see how setting the base in the html is the ultimate solution if your writing portable scripts and want to define a structure in a config file.
You’re welcome!
Consider reading my other post on the subject: Rewriting for SEO-Friendly URLs: .htaccess or PHP?
Personally, I don’t like to rely on mod_rewrite and recommend to do URI parsing work in PHP code.
What about WPO???. I had de Issue, i chose use the / at the beginning. but when you run a speed test like yslow you will find theres a lot of DNS lookups u need to clean.
absolute paths penalise you from DNS lookups. so thats why we need to find the way use relative paths as well.
of course if you get a CDN server you need full path on your images, js, etc.
but again, from this point of view a base tag, a slash, an absolute path is the same.
what i should try to do on a site is to make a rewrite rule without making any subfolder…
lets say.. if had:
http://www.domain.com/index.php?cat_id=4&name=blabla&page=4
i’d try to generate something like:
http://www.domain.com/blabla-4-4.html
so when apache redirects me, links will still the same (relatives)
the problem is that many times we’ve been sugested to make semantic friendly urls. So the pretty one would be:
http://www.domain.com/cat-4/page-4/blabla.html
from this point of view, what do you think ppl?
PD: im walking around this problem, so id love some suggestions.
MAT (Argentinian web developer)
If you store images, CSS and JS on some external server you may find it possible to refer to the server with IP address instead of domain name. Once URLs will contain IP addresses there will be no need to do a DNS lookup for them.
I found a solution from your site in which the problem already took 3 days to solve it. Much appreciate your work and efforts, thanks.
You’re welcome!
I had a problem with several sites where visitors were getting broken images and links for any relative path but it didnt’ happen to everyone and not in all browsers and I couldnt reproduce it on my PC, yet there it was when I looked on other ppls.. your base tag solution totally solved the issue which had been plaguing me for months! Thanks so much!
Nice to hear that you resolved that, Andrew.