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 offset
function offsetAnchor() {
if(location.hash.length !== 0) {
window.scrollTo(window.scrollX, window.scrollY - 100);
}
}
// This will capture hash changes while on the page
window.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 offset
function 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 url
window.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.