Make anchor link go some pixels above where it's linked to
window.addEventListener("hashchange", function () { window.scrollTo(window.scrollX, window.scrollY - 100);});
This will allow the browser to do the work of jumping to the anchor for us and then we will use that position to offset from.
EDIT 1:
As was pointed out by @erb, this only works if you are on the page while the hash is changed. Entering the page with a #something
already in the URL does not work with the above code. Here is another version to handle that:
// The function actually applying the offsetfunction offsetAnchor() { if(location.hash.length !== 0) { window.scrollTo(window.scrollX, window.scrollY - 100); }}// This will capture hash changes while on the pagewindow.addEventListener("hashchange", offsetAnchor);// This is here so that when you enter the page with a hash,// it can provide the offset in that case too. Having a timeout// seems necessary to allow the browser to jump to the anchor first.window.setTimeout(offsetAnchor, 1); // The delay of 1 is arbitrary and may not always work right (although it did in my testing).
NOTE:To use jQuery, you could just replace window.addEventListener
with $(window).on
in the examples. Thanks @Neon.
EDIT 2:
As pointed out by a few, the above will fail if you click on the same anchor link two or more times in a row because there is no hashchange
event to force the offset.
This solution is very slightly modified version of the suggestion from @Mave and uses jQuery selectors for simplicity
// The function actually applying the offsetfunction offsetAnchor() { if (location.hash.length !== 0) { window.scrollTo(window.scrollX, window.scrollY - 100); }}// Captures click events of all <a> elements with href starting with #$(document).on('click', 'a[href^="#"]', function(event) { // Click events are captured before hashchanges. Timeout // causes offsetAnchor to be called after the page jump. window.setTimeout(function() { offsetAnchor(); }, 0);});// Set the offset when entering page with hash present in the urlwindow.setTimeout(offsetAnchor, 0);
JSFiddle for this example is here
Working only with css you can add a padding to the anchored element (as in a solution above)To avoid unnecessary whitespace you can add a negative margin of the same height:
#anchor { padding-top: 50px; margin-top: -50px;}
I am not sure if this is the best solution in any case, but it works fine for me.
Even better solution:
<p style="position:relative;"> <a name="anchor" style="position:absolute; top:-100px;"></a> I should be 100px below where I currently am!</p>
Just position the <a>
tag with absolute positioning inside of a relatively positioned object.
Works when entering the page or through a hash change within page.