How do I set a page's base href in Javascript?
Asked Answered
M

5

38

I want to set a page's base href attribute in Javascript based off of the current hostname. I have generated HTML pages that can be viewed on different hostnames, which means generating a base href tag will work in one hostname but will be incorrect in the other.

Margalit answered 16/8, 2010 at 16:0 Comment(2)
I usually have a constants JS file that I include which i set $.serverRoot to be the relative root of the host (e.g. $.serverRoot = '/myapp/';Femininity
That works for things like AJAX requests, but if I were to adjust all of the image paths and link hrefs to account for a Javascript variable I'd have to do a tremendous amount of work. Using the base href tag solves a lot of problems I was having with having the same HTML file accessible on different hostnames, but it introduced the problem of incorrect paths on one hostname.Margalit
M
44

The correct way of doing this is to do a document.write of the tag based off the current hostname:

Correct:

<script type="text/javascript">
document.write("<base href='http://" + document.location.host + "' />");
</script>

This method has produced correct results in IE, FF, Chrome, and Safari. It produces a (correct) different result than doing the following:

Incorrect:

<script type="text/javascript">
var newBase = document.createElement("base");
newBase.setAttribute("href", document.location.hostname);
document.getElementsByTagName("head")[0].appendChild(newBase);
</script>
Margalit answered 16/8, 2010 at 16:4 Comment(10)
I have run into some trouble with Google's crawler while using this method. I didn't put a space between ' and />", and the crawler is intepreting my base href as document.location.hostname'/>. This may be a problem with this solution. For more information, see: google.com/support/forum/p/Webmasters/…Margalit
There is no reason presented why document.write would be “correct” and proper insertion of a node in the document tree would be “incorrect”. The question falls into the category “solving the wrong problem”, but the approach described as “correct” here would often insert a base tag in a wrong place, to begin with. If the code is in the head part, it’s rather useless (why not put the right base tag there as normal HTML?), and if it is executed elsewhere, it will usually insert base into body.Rotary
I'm curious as to why the "incorrect" method is incorrect.Felton
The "incorrect" method does not actually work. The only way to get the browser to dynamically change its base href is the "correct" method.Margalit
Hi! According to my tests in my angular enabled web page, the document.write mode don't seem to add the base tag until it is too late. I have compared the markup when adding it with javascript or hard-coding it in the markup, looks the same but js solution don't apply any base tag functionality even though "looks" like it is in place... Any ideas?Lanthanide
Shouldnt http: be document.location.protocol ?Risinger
I'm finding that on initial load, even though document.write is above stylesheet links and other assets, Chrome is first looking for files at the original url, and then trying again using the contents of <base />. For instance, if my original URL is site.dev/account, and the result of the document.write is setting base to site.dev, the assets are first trying to load from /account/, the server returns a 404, then they correctly load from site.dev.Mulloy
I'd just like to add a refinement: document.location.protocol + '//' + document.location.hostname + ( document.location.port ? ':' : '' ) + document.location.port + document.location.pathname + '" />' + document.head.innerHTML - this makes it more portable, for running on a specific port, such as in Webpack. this fixed a problem with Webpack for me, where Webpack can't write a different path for images in CSS than for images in HTML (they're all relative paths or all absolute paths, but not both, which prevents the app from being portable.)On
It would be great if this answer provided valuable information like... the answer to "why?"Tack
Considering the <base> is appended directly under the <script> tag... this "correct" method is basically useless, just use the <base> tag like normally. In fact, if you run the JS code in the devtool's console, it'll empty the entire DOM leaving just the base tag! The real correct method would be to use the document.head.innerHTML = "<base href=''>" + document.head.innerHTML as it ensures every element uses the new baseHref.Tack
G
14

I think you'd better do it this way

    <script type="text/javascript">
        document.head.innerHTML = document.head.innerHTML + "<base href='" + document.location.href + "' />";
    </script>

As location.hostname does not return the application context root! You could also log the document.location on the console console.log to see all available metadata on document.location.

Gravimeter answered 11/6, 2017 at 1:21 Comment(2)
This is actually more proper these days (than using document.write). On a practical note: this worked for me in jsFiddle while document.write didn't.Hacker
The ideal way would be to do document.head.innerHTML = "<base href=''>" + document.head.innerHTML (base first, then innerHTML) for two reasons: 1. Any <link> tags, <script> tags, etc in the <head> making use of the relative path, won't be able to since the <base> is being appended below them. 2. If you execute the code twice or more, the most recent execution becomes the <base> tag that works (because it's whichever is topmost that works and this code "prepends").Tack
M
6

I have to disagree with the top answer. It does not account for the protocol so it will fail.

A working solution that I have to account for protocol / host / port is the following

    var base = document.createElement('base');
    base.href = window.location.protocol + '//' + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
    document.getElementsByTagName('head')[0].appendChild(base);

This currently works fine in all major browsers including IE11

I have used this to make an npm package that also supports adding a suffix to the end of this base href if anyone is interested

https://www.npmjs.com/package/dynamic-base

https://github.com/codymikol/dynamic-base

Mesdemoiselles answered 12/9, 2019 at 15:51 Comment(5)
The <base> tag allows relative paths... this is pointless...Tack
Don't assume your usecase is the only one : V ). This post is from 2019 and having a fully qualified base href was required for me to use the ui.router library for angularjs and my application was hosted across many different domains.Mesdemoiselles
I don't get that because "Absolute and relative URLs are allowed", was that changed since 2019? Edit: Just checked the history doesn't seem to have changed since 2021. I think this was just a misconception, because unless it was changed, quite a few people seem to assume that <base> requires an absolute URL.Tack
Sure, but what if an external library that you don't have control of reads the base href and that particular library requires that to be a fully qualified url?Mesdemoiselles
The relative path you set is converted into an absolute url. If you do document.baseUri or inspect the properties of any element, you can see the baseHref property for each element on the DOM. The base href will be a "fully qualified url" based on the relative path you input into the <base href=""> tag.Tack
M
2
document.write("");

<script>
document.write("<base href='"+ window.location.protocol +'//' + window.location.host + "' >");
</script>
Mothering answered 26/8, 2016 at 4:29 Comment(0)
B
0
window.document.head.innerHTML=`<base href=${href}>`+window.document.head.innerHTML;

The href variable is the href you want to use.

Bumpy answered 12/5, 2023 at 22:45 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Parapsychology
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Parapsychology

© 2022 - 2024 — McMap. All rights reserved.