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 […]

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.

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

Before applying offset

Before applying an offset margin, the table-of-contents link scrolls 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 three ways to add margin offsets for anchor targets.

CSS Method 1: Add margin to target

The simplest possible 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 2: 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 3: 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.





Print Share Comment Cite Upload Translate
APA
Jeff Starr | Sciencx (2024-03-28T20:58:31+00:00) » Margin Offset for Anchor Targets with CSS or JavaScript. Retrieved from https://www.scien.cx/2023/01/24/margin-offset-for-anchor-targets-with-css-or-javascript/.
MLA
" » Margin Offset for Anchor Targets with CSS or JavaScript." Jeff Starr | Sciencx - Tuesday January 24, 2023, https://www.scien.cx/2023/01/24/margin-offset-for-anchor-targets-with-css-or-javascript/
HARVARD
Jeff Starr | Sciencx Tuesday January 24, 2023 » Margin Offset for Anchor Targets with CSS or JavaScript., viewed 2024-03-28T20:58:31+00:00,<https://www.scien.cx/2023/01/24/margin-offset-for-anchor-targets-with-css-or-javascript/>
VANCOUVER
Jeff Starr | Sciencx - » Margin Offset for Anchor Targets with CSS or JavaScript. [Internet]. [Accessed 2024-03-28T20:58:31+00:00]. Available from: https://www.scien.cx/2023/01/24/margin-offset-for-anchor-targets-with-css-or-javascript/
CHICAGO
" » Margin Offset for Anchor Targets with CSS or JavaScript." Jeff Starr | Sciencx - Accessed 2024-03-28T20:58:31+00:00. https://www.scien.cx/2023/01/24/margin-offset-for-anchor-targets-with-css-or-javascript/
IEEE
" » Margin Offset for Anchor Targets with CSS or JavaScript." Jeff Starr | Sciencx [Online]. Available: https://www.scien.cx/2023/01/24/margin-offset-for-anchor-targets-with-css-or-javascript/. [Accessed: 2024-03-28T20:58:31+00:00]
rf:citation
» Margin Offset for Anchor Targets with CSS or JavaScript | Jeff Starr | Sciencx | https://www.scien.cx/2023/01/24/margin-offset-for-anchor-targets-with-css-or-javascript/ | 2024-03-28T20:58:31+00:00
https://github.com/addpipe/simple-recorderjs-demo