46

Does window.location.hash contain the encoded or decoded representation of the url part?

When I open the same url (http://localhost/something/#%C3%BC where %C3%BCtranslates to ü) in Firefox 3.5 and Internet Explorer 8, I get different values for document.location.hash:

  • IE8: #%C3%BC
  • FF3.5:

Is there a way to get one variant in both browsers?

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
Michael
  • 8,920
  • 3
  • 38
  • 56

4 Answers4

39

Unfortunately, this is a bug in Firefox as it decodes location.hash an extra time when it is accessed. For example, try this in Firefox:

location.hash = "#%30";
location.hash === "#0"; // This is wrong, it should be "#%30"

The only cross-browser solution is to just use (location.href.split("#")[1] || "") instead for getting the hash. Setting the hash using location.hash seems to work correctly for all browsers that support location.hash though.

Eli Grey
  • 35,104
  • 14
  • 75
  • 93
  • Yep, that seems to be the most reasonable solution. – Michael Nov 10 '09 at 06:28
  • 1
    This test returns `false` under Firefox 10.0.1 at least. I'm not sure when it changed but of course if you want to support older versions this is still the best advice. – hippietrail Mar 14 '12 at 18:43
  • 1
    What if the hash part itself contains a #? In this case the split method won't work. – Christophe Aug 29 '12 at 02:39
  • 1
    thanks for your solution! just keep in mind that the output of location.hash has a leading "#" but location.href.split not.. – Tapper Jan 02 '13 at 09:34
  • 5
    @Christophe: Possible '#' in the hash itself ought to be encoded as '%23'. To be extra certain, you obviously can use `location.href.split('#').splice(1).join('#')`. In this case there's even no need to add `|| ""` because the result is an empty string if there's no hash in the first place. – Pekka Klärck Feb 13 '14 at 15:54
  • @PekkaKlärck the second # should not be encoded, it is an authorized character in the hash part of the url. – Christophe Feb 13 '14 at 16:25
  • "The only cross-browser solution is to just use (location.href.split("#")[1] || "")" I presume you meant `decodeURIComponent(location.href.split("#")[1] || ""))`, but this can fail in other cases e.g. https://jsfiddle.net/nsoaee4q/9/ – ChrisJJ Jan 09 '17 at 20:57
  • If you want to use split, I think you should use `location.href.split("#",2)[1] || ""` to split just by the first # – Jonas Berlin Jul 04 '19 at 06:03
6

Answering to my own question, my current solution is to parse window.location.href instead of using window.location.hash, because the former is always (i.e. in every browser) url-encoded. Therefore the decodeURIComponent function CMS proposed can always be used safely. YUI does the same, therefore it can't be that wrong...

Michael
  • 8,920
  • 3
  • 38
  • 56
5

You can use decodeURIComponent, it will return in all cases:

decodeURIComponent('#%C3%BC'); // #ü
decodeURIComponent('#ü'); // #ü

Try it out here.

Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 3
    Not a solution because: `decodeURIComponent('%2540'); // %40 (IE)` but `decodeURIComponent('%40'); // @ (FF)` – Michael Nov 09 '09 at 20:52
  • Not really sure about what you mean, %2540 is the `%` character encoded (`%25`) and the non encoded `40` string, `decodeURIComponent('%40');` is @ in IE or Firefox... http://jsbin.com/esafe – Christian C. Salvadó Nov 09 '09 at 21:09
  • 6
    Let's assume I wanted to use the hash for a search function and someone wants to search for `%40` (but not for `@`). Depending on his browser, I will get `#%2540` (IE) or `#%40` (FF) as `location.hash`. If I decode it then, I get different results in the different browsers. – Michael Nov 09 '09 at 22:00
0

Actually in my version of Firefox (3.5 on Linux), if I type "#%C3%BC" as a hash in the URL, the URL itself actually transforms to unicode with "#ü". But you have appeared to answered your own question -- in Firefox, the browser transforms entity escape codes in the URL, while in IE, it does not.

My advice is actually this: Instead of putting "#%C3%BC" in the URL at all, just use full unicode in your hashes and URLs. Is that an option? It should work fine in any modern browser.

Ken Kinder
  • 12,654
  • 6
  • 50
  • 70
  • 3
    No, it's not :(. Your Firefox (and mine too) is just pretending to use an `ü` character. In HTTP it always uses the percent-encoding. Move your mouse over that link: http://test/%C3%BC. The Firefox status bar shows an `ü` for some reason. But if you use an HTTP sniffer, you will find out, that it's submitting `%C3%BC`. And basically, because I'm using that one in a HTTP redirect, I can not directly use unicode characters anyway. – Michael Nov 09 '09 at 20:38
  • Are you sure that doesn't depend on the encoding being ASCII v a unicode encoding? – Ken Kinder Nov 09 '09 at 20:56
  • AFAIK there is no way to transfer unicode characters in HTTP without special preparation like the percent-encoding (because HTTP does not allow characters outside the ASCII range). – Michael Nov 09 '09 at 22:03