Ever click an anchor link and have it jump to exactly the top of the page, squished right under your fixed header? Not ideal.
You might have a sticky menu, an announcement banner, or you just want some breathing room. Whatever the reason, you need to offset that anchor.
The Problem
When you navigate to yoursite.com/page#section, the browser scrolls so that element is flush with the top of the viewport. This often means:
- Content hidden behind fixed headers
- Zero visual spacing (looks cramped)
- Poor user experience
Why Other CSS Solutions Don’t Work
You might have heard about CSS properties like scroll-padding-top or scroll-margin-top. In theory, these are perfect for this exact problem:
html {
scroll-padding-top: 80px;
}
/* or */
#target-section {
scroll-margin-top: 80px;
}
And they do work… most of the time. The problem? Browser support is still inconsistent, especially with smooth scrolling, JavaScript scroll implementations, and certain mobile browsers. The scroll-padding-top property is great when it works, but it’s still a bit buggy across different contexts.
Hopefully we can use it everywhere soon. Until then, we need a reliable workaround.
The Solution
Use a CSS pseudo-element to create an invisible anchor point above your section. This approach works across all browsers and has been reliable for years.
One-Off Usage (Inline CSS)
If you only need this on one or two elements, add it inline:
<section id="target-section" style="position: relative;">
<style>
#target-section::before {
content: '';
display: block;
position: relative;
width: 0;
height: 0;
top: -60px;
visibility: hidden;
}
</style>
Multiple Elements (Stylesheet)
For reuse across multiple pages, add this to your main stylesheet as a class, then override the offset per ID:
.anchor-offset {
position: relative;
}
.anchor-offset::before {
content: '';
display: block;
position: relative;
width: 0;
height: 0;
visibility: hidden;
}
#target-section::before {
top: -120px;
}
#about-us::before {
top: -80px;
}
#contact-form::before {
top: -100px;
}
Then add the class to each anchor target:
<section id="target-section" class="anchor-offset">
<div id="about-us" class="anchor-offset">
<div id="contact-form" class="anchor-offset">
Handling Mobile
Adjust offsets for smaller headers with media queries:
@media (max-width: 768px) {
#target-section::before {
top: -80px;
}
}
No JavaScript, no extra divs, works everywhere. Done.





