Save 25% on Wizard’s SQL for WP w/ code: WIZARDSQL
Web Dev + WordPress + Security

Margin Offset for Anchor Targets with CSS or JavaScript

For sites using a fixed-position “sticky” header or similar, it’s necessary to add an offset margin to any on-page anchor targets. For example this recent article provides a Table of Contents menu with links to each section on the page. Click a link and the page scrolls down to the target element, which is an <h2> heading tag. Thanks to one of the CSS solutions provided in this tutorial, the scrolling takes into account the page’s 50-pixel sticky header, so the heading text is fully visible on the page.

Contents

Here are some “before” and “after” screenshots to help visualize the idea..

Before applying offset

Before applying an offset margin, the table-of-contents “jump links” scroll down to the default location. Because the page has a sticky header, the default position is not quite far enough. And the result is obscured heading text, covered by the sticky header, unreadable and awkward for the user.

Screenshot showing incorrect margin offsetScreenshot showing incorrect margin offset for an anchor target (before applying fix)

After applying offset

After applying an offset margin, the table-of-contents link scrolls down to the correct location. The extra margin added to the target element provides sufficient vertical space. So the heading text is displayed fully and looks good, etc.

Screenshot showing correct margin offsetScreenshot showing correct margin offset for an anchor target (after applying fix)

You can try it out for yourself on any page with a table of contents (assuming the site’s current design still makes use of a sticky header). That’s the issue we’re solving in this tutorial. Here are four ways to add margin offsets for anchor targets.

CSS Method 1: Use scroll-margin-top

The simplest way to add offset margins is to use scroll-margin-top.

.target-element { scroll-margin-top: 50px; }

Super simple and works on all major browsers (except of course IE). It’s not quite yet universally supported by all browsers, so if you’re going for 100% support, any of the other methods should get you there. Thanks to Dick Raney and this post over at CSS-Tricks for information about this technique.

Upside: Super simple and literally designed for adding offset margins.

Downside: Currently not as widely supported as other techniques.

CSS Method 2: Add margin to target

Another simple solution is to add the following line of CSS:

.target-element { margin-top: -50px; padding-top: 50px; }

You’ll want to change the 50px to match the desired offset distance. For example, if the sticky header height is 90px, you’ll want to change the 50px to 100px or more. For best results, both margin and padding values should be the same. Whatever is needed to give plenty of vertical space for the target element to display properly.

Upside: Super simple and lightweight technique.

Downside: Doesn’t work with all layouts, watch out for floats and borders.

CSS Method 3: Add margin *before* target

The next best solution is to add the following line of CSS:

:target::before { content: ''; display: block; height: 50px; margin: -50px 0 0 0; }

As before, change the 50px to match the desired offset distance. For best results, both margin and padding values should be the same. Whatever is needed to give plenty of vertical space for the target element to display properly. This is the technique used here at Perishable Press (current theme/design).

Upside: Simple, lightweight and gracefully degrading.

Downside: None, but be careful if the target element has any visible border. For example, border-left: 10px solid #DD6D0B.

Method 4: Add margin using JavaScript or jQuery

JavaScript

As you might suspect, margin offsets also can be applied using a bit of jQuery or JavaScript. First, here is the vanilla JavaScript technique:

window.addEventListener('hashchange', offsetAnchor);
window.setTimeout(offsetAnchor, 1);
function offsetAnchor() {
	if (location.hash.length !== 0) {
		window.scrollTo(window.scrollX, window.scrollY - 50);
	}
}

The beauty of this technique is that it just works. Simply add to your site’s CSS and done. Of course, you may need to change the 50 (pixels) to whatever is required.

jQuery

Here is how to implement using a few lines of jQuery:

var offset = $(':target').offset();
var scrollto = offset.top - 50; // minus fixed header height
$('html, body').animate({ scrollTop:scrollto }, 0);

Same as before, change the 50 to whatever suits your design.

Upside: Using JavaScript/jQuery separates behavior from appearance.

Downside: Heavy handed for something easily done with simple CSS.

That’s all folks, thanks for reading.

Jeff Starr
About the Author
Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
GA Pro: Add Google Analytics to WordPress like a pro.

2 responses to “Margin Offset for Anchor Targets with CSS or JavaScript”

Leave a reply

Name and email required. Email kept private. Basic markup allowed. Please wrap any small/single-line code snippets with <code> tags. Wrap any long/multi-line snippets with <pre><code> tags. For more info, check out the Comment Policy and Privacy Policy.

Subscribe to comments on this post

Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
Blackhole Pro: Trap bad bots in a virtual black hole.
Thoughts
DIY: Monitor File Changes via Cron working perfectly for over a decade.
Mastodon social is a trip. Glad I found it.
As a strict rule, I never use cache plugins on any of my sites. They cause more problems than they solve, imho. Just not worth it.
Currently on a posting spree :)
6 must come before 7.
My top three favorite-to-write coding languages: CSS, PHP, JavaScript.
If you’re not 100% sure that you can trust something, you can’t.
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.