What: CSS-Tricks just posted about this last Friday and since I could have used this that day (!) but didn’t find it until now, I’m adding a note here for myself:
You have a page with a table of contents (with links), or you have a one page website with in-page navigation and you have a fixed header — when you click a link the content scrolls up too far and is hidden by the fixed header. This is not a good user experience, and you can improve it with scroll-margin-top
in Firefox and Chrome-based browsers…
How: Use scroll-margin-top
on the item that is being covered by the fixed header, like so:
The CSS
header { position: fixed; top: 0; width: 100%; height: 6em; }
h3 { scroll-margin-top: 6em; }
The HTML
<header>My fab website</header>
<main>
<nav class="table-of-contents">
<ul>
<li><a href="#topic-1">Topic 1</a></li>
<li><a href="#topic-2">Topic 2</a></li>
<li><a href="#topic-3">Topic 3</a></li>
</ul>
</nav>
<section>
<h3 id="topic-1">Topic 1</h3>
<p>A whole bunch of text.</p>
</section>
<section>
<h3 id="topic-2">Topic 2</h3>
<p>A whole bunch of text.</p>
</section>
<section>
<h3 id="topic-3">Topic 3</h3>
<p>A whole bunch of text.</p>
</section>
</main>
Where: as said, Chris Coyier wrote about it @ CSS-Tricks
Thoughts: Support is not very good: IE, Safari, iOS and old Edge all have no support.
On Friday I decided, since it was a rush job and I didn’t have time for complex hacks or prolonged research, that in this case the table of contents was more important than the fixed header and I nixed the fixed header. Since cross-browser support is not very good, I still think that is the best solution in this case, but I might add some scroll-margin-top anyway, just to make it look a bit nicer, when people scroll–not quite as cramped.
EDITS: As a lovely person pointed out, I actually wrote margin-scroll-top
in one instance instead of scroll-margin-top
.
The same lovely person also asked if I knew how to make this work in iOS and … that stopped me because I had in my mind that browser support was good. I checked this post and that was in fact what it said “Support is very good” even with a link to Can I Use which, when I looked again, yes, the Safari and iOS boxes where vaguely green but with those little numbers in them implying caveats… and the caveats mean, in this case, that it doesn’t work in Safari or iOS.
You would have to use scroll-snap-margin-top
instead of scroll-margin-top
and this is because Safari has implemented it as part of the CSS scroll snap module, which means it is only to be used with scroll snap containers. Since that’s not what we’re doing here, it won’t work in Safari or iOS, I am sad to say.
The simplest solution with good cross-browser support is still this one:
h3 {
padding-top: 6em;
margin-top: -6em;
}
Source: stackoverflow
I am very sorry for my earlier sloppiness and I updated this post to make it clear right away.
Also: thank you very much, lovely person who let me know! I’m sorry I don’t have better news, but I appreciate you emailing me about this.
In general, comments and emails to let me know things like this, or to ask me anything, are always welcome!
The note on Safari, and that Safari will use `scroll-snap-margin-top` is something I didn’t find anywhere else, even Stack Overflow. Thanks so much for posting this–now it works for me in Safari!
The padding + negative margin hack is no good if you need to draw borders or background.
For alternative hack that has similar problems but is more generic:
:target::before
{
content: “”;
display: block;
height: 4rem;
margin-top: -4rem;
width: 1px;
visibility: hidden;
pointer-events: none;
}
However, because :before will be inserted inside the target element, it will cause the target element to increase in size and e.g. border will still draw incorrectly.
This is such a great fix. Thanks it safe my day today 🙂
Thank you so much!!!!!! Really useful
Dear Sir
Thank you so much for such a nice tip. I have been looking for this solutin for last many days.
Greeting from Germany