BlogCSS fixes
Anchor links that land under your Webflow navbar
The browser lands the section at the very top of the window, exactly where your sticky header is sitting.
Break it yourself
A live demo. It measures its own result in your browser.
Pricing
Process
FAQ
Use the links in the demo header to jump.
When a Webflow anchor link hides the section heading under your navbar, the browser is doing what it was told: it lines the top of the target up with the top of the window, exactly where your sticky header sits. Give the targets a scroll-margin-top equal to the header height and every in-page link on the site lands below it.
The short answer
Webflow does not offset anchor jumps for a sticky navbar on its own. When someone clicks a link to #pricing, the browser scrolls until the top edge of the element with that ID meets the top edge of the viewport. A sticky or fixed navbar is drawn over that same strip, so the first part of the section, usually the heading, ends up underneath it.
The fix is one CSS value. Put scroll-margin-top on the targets, or scroll-padding-top on the html element, set to the header height plus a little space. Both tell the browser to stop short by that amount. One rule covers every anchor link, every button that points at a section, and every visitor who arrives from a URL with a hash in it.
Why Webflow anchor links land under the navbar
When the browser scrolls to a fragment, it does not account for anything pinned over the page. It aligns the target’s top edge with the top of the scroll area, and whatever is stuck to that area covers what lands there. From the browser’s side, the jump worked perfectly.
Many sites patch this with a script: catch the click, read the target’s position, subtract a number, scroll. It works on the day it is written and drifts as soon as the header changes, because nothing ties the number to the header.
That is exactly what happened on our own site. Our in-page links scrolled with a hard-coded offset of 70px, while the sticky header area was 103px tall, and no target had a scroll-margin-top. We measured the header covering the top 87px of all eight anchor targets on the page. One scroll-margin-top rule fixed all eight links and a button that scrolled to a section, and the magic number in the script went away.
How to measure the overlap
In the Webflow Designer
- Select the navbar and check Position in the Style panel: both Sticky and Fixed cause the overlap. Note its height, including any announcement bar above it that is pinned too.
- Select a target section and read its ID in the Element settings panel. That ID is what the link points at.
- Look at the section’s top padding. A section with generous padding may clear the header by luck, which is why only some of your anchors misbehave.
The 30 second check in DevTools
- Open the published page and click one of the anchor links, so the URL ends in a hash.
- Right-click the navbar, choose Inspect, and read its
heightin the Computed tab. - Inspect the target and look for
scroll-margin-topin Computed. If it reads0px, nothing is offsetting the jump. - Paste the snippet below into the Console, with your own header class in the first line. A positive number is the number of pixels hidden under the header.
const header = document.querySelector('.navbar');
const target = document.querySelector(location.hash);
const hidden = header.getBoundingClientRect().bottom
- target.getBoundingClientRect().top;
console.log(Math.round(hidden) + 'px of the target is under the header');That number, plus some breathing room, is the offset you need.
The fix: scroll-margin-top on the targets
Webflow has no dedicated setting for this, but the Style panel accepts any CSS property in its Custom Properties section at the bottom. There are two clean ways to apply the offset.
Option 1: on the targets
Add scroll-margin-top to the class your sections already use, through Custom Properties. Better still, keep the header height in one CSS variable and read it in both places, so the offset follows the header whenever it changes:
:root {
--header-h: 96px;
}
.navbar {
height: var(--header-h);
}
[id] {
scroll-margin-top: calc(var(--header-h) + 16px);
}The [id] selector matches every element with an ID, which is every possible anchor target. The Style panel styles classes, so a rule like this goes into a style tag in the head code under Site settings › Custom code, or in Page settings if only one page has anchors. The 96px and 16px here are examples: use the height you measured.
Option 2: once on the html element
html {
scroll-padding-top: calc(var(--header-h) + 16px);
}This sets the offset on the page’s scroll container instead of on each target. It is one line, and it covers targets you add later without any class. We use the target version when different sections need different offsets, and this one when the offset is the same everywhere.
Once the CSS is in, remove any script that subtracts a fixed number. A script that scrolls with scrollIntoView already respects the CSS offset, so a subtraction on top of it counts the header twice.
Other things that move the landing spot
The header changes height at a breakpoint
A navbar that is shorter on phones needs a shorter offset there. With the height in one variable, that is a single override of --header-h inside the matching media query, and both the header and the offset follow it.
A banner sits above the navbar
A pinned announcement bar adds to the covered strip. Measure from the top of the window to the bottom of the last pinned element, not just the navbar.
The target sits inside an overflow hidden wrapper
A box with overflow hidden can still be scrolled by an anchor jump, so the jump may shift the wrapper’s clipped content as well as the page. The same wrapper is a common reason a sticky navbar stops sticking, and the fix there, overflow clip, helps here too.
Content loads in above the target after the jump
Images without set dimensions, or embeds that load late, push the target down after the browser has already scrolled. Give images a width and height or an aspect ratio so the layout is final before the jump happens.
How to keep anchors and the header in sync
- One number for the header height. Define it once and read it in the header and in the offset. Two copies of the same number drift apart, which is how we ended up with 70 against 103.
- No offsets in scripts. Let CSS own the offset, and let scripts call the browser’s own scrolling.
- Click every anchor after any header change, at every breakpoint, and run the snippet once on each. It takes a minute and gives you a number instead of an impression.
Headers change often, and anchors break silently when they do, which is why this check belongs in regular website maintenance and support rather than in a one-off launch list.