javascript - wrong - wordpress anchor links with fixed header




offsetting an html anchor to adjust for fixed header (19)

You can do it without js and without altering html. It´s css-only.

a[id]:before {
    content:"";
    display:block;
    height:50px;
    margin:-30px 0 0;
}

That will append a pseudo-element before every a-tag with an id. Adjust values to match the height of your header.

This question already has an answer here:

I am trying to clean up the way my anchors work. I have a header that is fixed to the top of the page, so when you link to an anchor elsewhere in the page, the page jumps so the anchor is at the top of the page, leaving the content behind the fixed header (I hope that makes sense). I need a way to offset the anchor by the 25px from the height of the header. I would prefer HTML or CSS, but Javascript would be acceptable as well.


@AlexanderSavin's solution works great in WebKit browsers for me.

I additionally had to use :target pseudo-class which applies style to the selected anchor to adjust padding in FF, Opera & IE9:

a:target {
  padding-top: 40px
}

Note that this style is not for Chrome / Safari so you'll probably have to use css-hacks, conditional comments etc.

Also I'd like to notice that Alexander's solution works due to the fact that targeted element is inline. If you don't want link you could simply change display property:

<div id="myanchor" style="display: inline">
   <h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</div>

Adding to Ziav's answer (with thanks to Alexander Savin), I need to be using the old-school <a name="...">...</a> as we're using <div id="...">...</div> for another purpose in our code. I had some display issues using display: inline-block -- the first line of every <p> element was turning out to be slightly right-indented (on both Webkit and Firefox browsers). I ended up trying other display values and display: table-caption works perfectly for me.

.anchor {
  padding-top: 60px;
  margin-top: -60px;
  display: table-caption;
}

As @moeffju suggests, this can be achieved with CSS. The issue I ran into (which I'm surprised I haven't seen discussed) is the trick of overlapping previous elements with padding or a transparent border prevents hover and click actions at the bottom of those sections because the following one comes higher in the z-order.

The best fix I found was to place section content in a div that is at z-index: 1:

// Apply to elements that serve as anchors
.offset-anchor {
  border-top: 75px solid transparent;
  margin: -75px 0 0;
  -webkit-background-clip: padding-box;
  -moz-background-clip: padding;
  background-clip: padding-box;
}

// Because offset-anchor causes sections to overlap the bottom of previous ones,
// we need to put content higher so links aren't blocked by the transparent border.
.container {
  position: relative;
  z-index: 1;
}

Borrowing some of the code from an answer given at this link (no author is specified), you can include a nice smooth-scroll effect to the anchor, while making it stop at -60px above the anchor, fitting nicely underneath the fixed bootstrap navigation bar (requires jQuery):

$(".dropdown-menu a[href^='#']").on('click', function(e) {
   // prevent default anchor click behavior
   e.preventDefault();

   // animate
   $('html, body').animate({
       scrollTop: $(this.hash).offset().top - 60
     }, 300, function(){
     });
});

FWIW this worked for me:

*[id]:before { 
  display: block; 
  content: " "; 
  margin-top: -75px; 
  height: 75px; 
  visibility: hidden; 
}

For the same issue, I used an easy solution : put a padding-top of 40px on each anchor.


Here's the solution that we use on our site. Adjust the headerHeight variable to whatever your header height is. Add the js-scroll class to the anchor that should scroll on click.

// SCROLL ON CLICK
// --------------------------------------------------------------------------
$('.js-scroll').click(function(){
    var headerHeight = 60;

    $('html, body').animate({
        scrollTop: $( $.attr(this, 'href') ).offset().top - headerHeight
    }, 500);
    return false;
});

I found this solution:

<a name="myanchor">
    <h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</a>

This doesn't create any gap in the content and anchor links works really nice.


I had been facing a similar issue, unfortunately after implementing all the solutions above, I came to the following conclusion.

  1. My inner elements had a fragile CSS structure and implementing a position relative / absolute play, was completely breaking the page design.
  2. CSS is not my strong suit.

I wrote this simple scrolling js, that accounts for the offset caused due to the header and relocated the div about 125 pixels below. Please use it as you see fit.

The HTML

<div id="#anchor"></div> <!-- #anchor here is the anchor tag which is on your URL -->

The JavaScript

 $(function() {
  $('a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') 
&& location.hostname == this.hostname) {

      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top - 125 //offsets for fixed header
        }, 1000);
        return false;
      }
    }
  });
  //Executed on page load with URL containing an anchor tag.
  if($(location.href.split("#")[1])) {
      var target = $('#'+location.href.split("#")[1]);
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top - 125 //offset height of header here too.
        }, 1000);
        return false;
      }
    }
});

See a live implementation here.


I was looking for a solution to this as well. In my case it was pretty easy.

I have a list menu with all the links:

<ul>
<li><a href="#one">one</a></li>
<li><a href="#two">two</a></li>
<li><a href="#three">three</a></li>
<li><a href="#four">four</a></li>
</ul>

And below that the headings where it should go to.

<h3>one</h3>
<p>text here</p>

<h3>two</h3>
<p>text here</p>

<h3>three</h3>
<p>text here</p>

<h3>four</h3>
<p>text here</p>

Now because I have a fixed menu at the top of my page I can't just make it go to my tag because that would be behind the menu.

Instead I put a span tag inside my tag with the proper id.

<h3><span id="one"></span>one</h3>

Now use 2 lines of css to position them properly.

h3{ position:relative; }
h3 span{ position:absolute; top:-200px;}

Change the top value to match the height of your fixed header (or more). Now I assume this would work with other elements as well.


I'm facing this problem in a TYPO3 website, where all "Content Elements" are wrapped with something like:

<div id="c1234" class="contentElement">...</div>

and i changed the rendering so it renders like this:

<div id="c1234" class="anchor"></div>
<div class="contentElement">...</div>

And this CSS:

.anchor{
    position: relative;
    top: -50px;
}

The fixed topbar being 40px high, now the anchors work again and start 10px under the topbar.

Only drawback of this technique is you can no longer use :target.


My solution combines the target and before selectors for our CMS. Other techniques don't account for text in the anchor. Adjust the height and the negative margin to the offset you need...

:target:before {
    content: "";
    display: inline-block;
    height: 180px;
    margin: -180px 0 0;
}

Pure css solution inspired by Alexander Savin:

a[name] {
  padding-top: 40px;
  margin-top: -40px;
  display: inline-block; /* required for webkit browsers */
}

Optionally you may want to add the following if the target is still off the screen:

  vertical-align: top;

The above methods don't work very well if your anchor is a table element or within a table (row or cell).

I had to use javascript and bind to the window hashchange event to work around this (demo):

function moveUnderNav() {
    var $el, h = window.location.hash;
    if (h) {
        $el = $(h);
        if ($el.length && $el.closest('table').length) {
            $('body').scrollTop( $el.closest('table, tr').position().top - 26 );
        }
    }
}

$(window)
    .load(function () {
        moveUnderNav();
    })
    .on('hashchange', function () {
        moveUnderNav();
    });

* Note: The hashchange event is not available in all browsers.


This takes many elements from previous answers and combines into a tiny (194 bytes minified) anonymous jQuery function. Adjust fixedElementHeight for the height of your menu or blocking element.

    (function($, window) {
        var adjustAnchor = function() {

            var $anchor = $(':target'),
                    fixedElementHeight = 100;

            if ($anchor.length > 0) {

                $('html, body')
                    .stop()
                    .animate({
                        scrollTop: $anchor.offset().top - fixedElementHeight
                    }, 200);

            }

        };

        $(window).on('hashchange load', function() {
            adjustAnchor();
        });

    })(jQuery, window);

If you don't like the animation, replace

$('html, body')
     .stop()
     .animate({
         scrollTop: $anchor.offset().top - fixedElementHeight
     }, 200);

with:

window.scrollTo(0, $anchor.offset().top - fixedElementHeight);

Uglified version:

 !function(o,n){var t=function(){var n=o(":target"),t=100;n.length>0&&o("html, body").stop().animate({scrollTop:n.offset().top-t},200)};o(n).on("hashchange load",function(){t()})}(jQuery,window);

You can achieve this without an ID using the a[name]:not([href]) css selector. This simply looks for links with a name and no href e.g. <a name="anc1"></a>

An example rule might be:

a[name]:not([href]){
    display: block;    
    position: relative;     
    top: -100px;
    visibility: hidden;
}

You can also add an anchor with follow attr:

(text-indent:-99999px;)
visibility: hidden;
position:absolute;
top:-80px;    

and give the parent container a position relative.

Works perfect for me.


how about hidden span tags with linkable IDs that provide the height of the navbar:

#head1 {
  padding-top: 60px;
  height: 0px;
  visibility: hidden;
}


<span class="head1">somecontent</span>
<h5 id="headline1">This Headline is not obscured</h5>

heres the fiddle: http://jsfiddle.net/N6f2f/7







offset