If I have a non-scrolling header in an HTML page, fixed to the top, having a defined height:
Is there a way to use the URL anchor (the #fragment
part) t
Official Bootstrap Adopted Answer:
*[id]:before {
display: block;
content: " ";
margin-top: -75px; // Set the Appropriate Height
height: 75px; // Set the Appropriate Height
visibility: hidden;
}
Credits
Merge
I needed something that works for inbound links, links on page, AND that can be targeted by JS so the page can respond to changes in the header height
HTML
<ul>
<li><a href="#ft_who">Who?</a></li>
<li><a href="#ft_what">What?</a></li>
<li><a href="#ft_when">When?</a></li>
</ul>
...
<h2 id="ft_who" class="fragment-target">Who?</h2>
...
<a href="#">Can I be clicked?</a>
<h2 id="ft_what" class="fragment-target">What?</h2>
...
<h2 id="ft_when" class="fragment-target">When?</h2>
CSS
.fragment-target {
display: block;
margin-top: -HEADER_HEIGHTpx;
padding-top: HEADER_HEIGHTpx;
z-index: -1;
}
The z-index: -1
allows links in the 'padding area' above a fragment-target to still be clickable, as commented by @MuttenXd on his answer
I haven't found an issue yet in IE 11, Edge 15+, Chrome 38+, FF 52+, or Safari 9.1+
I use this approach:
/* add class="jumptarget" to all targets. */
.jumptarget::before {
content:"";
display:block;
height:50px; /* fixed header height*/
margin:-50px 0 0; /* negative fixed header height */
}
It adds an invisible element before each target. It works IE8+.
Here are more solutions: http://nicolasgallagher.com/jump-links-and-viewport-positioning/
While some of the proposed solutions work for fragment links (= hash links) within the same page (like a menu link that scrolls down), I found that none of them worked in current Chrome when you want to use fragment links coming in from other pages.
So calling www.mydomain.com/page.html#foo from scratch will NOT offset your target in current Chrome with any of the given CSS solutions or JS solutions.
There is also a jQuery bug report describing some details of the problem.
SOLUTION
The only option I found so far that really works in Chrome is JavaScript that is not called onDomReady but with a delay.
// set timeout onDomReady
$(function() {
setTimeout(delayedFragmentTargetOffset, 500);
});
// add scroll offset to fragment target (if there is one)
function delayedFragmentTargetOffset(){
var offset = $(':target').offset();
if(offset){
var scrollto = offset.top - 95; // minus fixed header height
$('html, body').animate({scrollTop:scrollto}, 0);
}
}
SUMMARY
Without a JS delay solutions will probably work in Firefox, IE, Safari, but not in Chrome.
You could try this:
<style>
h1:target { padding-top: 50px; }
</style>
<a href="#bar">Go to bar</a>
<h1 id="bar">Bar</h1>
Set the top padding value to the actual height of your header. This will introduce a slight extra gap at the top of your header, but it will only be visible when the user jumps to the anchor and then scrolls up. I've made up that solution for my site right now, but it only shows a small fixed bar at the top of the page, nothing too high.
The way that I find being the cleanest is the following one :
#bar::before {
display: block;
content: " ";
margin-top: -150px;
height: 150px;
visibility: hidden;
pointer-events: none;
}