Spring Sale! Save 30% on all books w/ code: PLANET24
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.

About the Author
Jeff Starr = Web Developer. Book Author. Secretly Important.
.htaccess made easy: Improve site performance and security.

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

Comments are closed for this post. Something to add? Let me know.
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 »
GA Pro: Add Google Analytics to WordPress like a pro.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.