Catch those anchors with hash && (hash = hash)
The following cryptic bit of JavaScript is actual code that I’ve used as a workaround to a very specific issue. The issue I was having was with anchor links not pointing to the right place on the page.
It was a single page with the top navigation pointing to sections within the page, but the issue was that the position of the section anchors were shifting due to progressive enhancement being applied when the page loads. I was cloning the top navigation to the top of each section for easier navigation. When the page was visited with a particular anchor from an external link or a bookmark, the vertical scroll location was pointing to the original position of the anchor, with the cloned navigation pushed off screen.
Interestingly, among all the browsers that I’ve tested, only Firefox seemed to exhibit this behaviour. It looks like Firefox handles scrolling to anchor destinations before the onload handler has a chance to alter the DOM.
The full context of the workaround is:
setTimeout(function () {
with (document.location) hash && (hash = hash);
}, 1);
This is basically saying:
If there’s an anchor (hash) in the URL, go (again) to that anchor after a 1 millisecond delay.
The 1 millisecond delay hack allows a piece of JavaScript to be asynchronously executed after the running of the current thread is complete. This is to ensure the DOM manipulations are complete and everything is rendered as intended. Setting the document.location.hash property to its own value lets the browser scroll to the actual, updated location of the anchor the page.
See the scenario in action (requires Firefox). You should be taken to the top of the first paragraph while you should have been taken to the top of the navigation above it. If you examine the DOM, you’ll see that the id (first) of the paragraph has been moved to the cloned navigation above it.
And here’s the workaround in action. You should be taken to the top of the navigation instead of the top of the paragraph.
Admittedly, this is a self-inflicted problem that I could have completely avoided instead of reverting to this workaround. The way to avoid this problem would be to simply clone the navigation into the target paragraph (or a wrapping div) instead of before it. Maybe I’ll update my page later to do just that…