I ran into an issue recently where I wanted to use anchors to jump to different sections within a long web page. The problem was every time I clicked the page would jump, but a fixed header would cover part of each section’s content.

After a bit of searching, some trial and error, a simple HTML adjustment and a bit of CSS and the problem was solved.

The Setup and the Problem

I started with a header that was set up like so: (styles inlined for clarification)

<div class="header" style="position: fixed; top: 0;"></div>

Near the top of the page was an unordered list that contains the anchor links:

<ul>
  <li><a href="#section1">Anchor Text</a></li>
  <li><a href="#section2">Anchor Text</a></li>
  <li><a href="#section3">Anchor Text</a></li>
</ul>

And of course, there was each section of content which I wanted to jump to:

<div class="section" id="section1"></div>
<div class="section" id="section2"></div>
<div class="section" id="section3"></div>

Now as you can see, I started with adding the IDs to each section. This is when I noticed that clicking on one of the anchor links would actually cause the page to jump to the right section, but some of the content in the section would get covered by the header which is fixed and stays at the top of the page when scrolling occurs.

To overcome the issue a minor HTML adjustment was made and a small amount of CSS was also added to bring it all together.

The Solution That Worked

First, I moved the id’s of each section to a new element: (a span in this case)

<span class="anchor" id="section1"></span>
<div class="section"></div>

<span class="anchor" id="section2"></span>
<div class="section"></div>

<span class="anchor" id="section3"></span>
<div class="section"></div>

The new <span> elements were added right above each section and would serve as the new anchor point. I’m not the biggest fan of empty elements on a page, but it does address the issue.

Once the new <span> elements were in place, a bit of CSS was added:

.anchor{
  display: block;
  height: 115px; /*same height as header*/
  margin-top: -115px; /*same height as header*/
  visibility: hidden;
}

The height and margin-top numbers are based on the height of the header. Using the Chrome developer tools, this number is easy to figure out.

After these simple adjustments, it was time to jump back in the browser and test it out. Clicking the anchor link jumped down the page and the <span> corrected the space for the header and voilà – The page now jumps correctly!

Discussion

  1. I searched for quite some time to find a fix for this problem and could not find nothing except js fixes. This solution worked amazingly well and was simple to impliment. Thank you so much!

  2. This was very helpful!

    I attempted to make something that worked with default anchor codes using the [name] selector and psuedo elements. Here’s what I’ve come up with so far: http://jsfiddle.net/shshaw/VujcA/

    Chrome & Safari work without a hitch, IE8 works mostly as expected, Firefox doesn’t like semantic anchors & IE7 is just gross.

    Anyone else willing to take a stab?

  3. That was awesome help, thanks! I have been trying to figure this out for a couple of hours. Awesome!!

  4. Hi Patrick,

    I took a look at your site and it appears you are missing the negative margin and visibility css properties. Please try adjusting your CSS:

    .anchor {
    display: block;
    height: 213px;
    margin-top:-213px;
    visibility:hidden;
    }

    Hope that helps!

  5. I have to salute you, these handful lines of code do the trick!

    I was close to completely going nuts before :-)

  6. This is a good solution, I had not considered this before. I have had similar problems and found that adding padding to the div can also be effective as long as it works with the layout of your site.

  7. Greetings! This is my first comment here so I just
    wanted to give a quick shout out and tell you I really enjoy reading through your articles.
    Can you recommend any other blogs/websites/forums that cover the
    same subjects? Thank you so much!

  8. Watch out for the negative value, as with Patrick Haroldson, that caught me out too.

    Once the negative value is fixed, the gaps disappear. This works really well. Great work, Phillip, well done. And thank you.

  9. Hye Philips

    This was truly a meaningful post. Three cheers to you man !!
    I was struggling for past 2 hours on this topic and was not able to find any clue on how to do it in simple measure. Your answers was Bull’s eye , straight to the goal.

    Thanks :)

  10. Phillip, this saved me quite a bit of trouble… Gracias, amigo!!
    A new fan from Argentina

  11. AWESOME. Seriously, I’ve been stuck with this same problem for days. Glad I found such a simple fix. THANK YOU!!!

  12. Thank you kind sir, one correction though, for the sake of people that will copy-paste your code, please correct the commented part of the anchor css class like this:
    .anchor {
    display: block;
    height: 115px; /* same height as header */
    margin-top: -115px; /* same height as header */
    visibility: hidden;
    }

  13. This is exactly what I was looking for – I was struggling for a solution. Thank you for posting!!

  14. I, as well, have been searching for an intuitive solution for this problem, and this works like a dream. Thank you so much!

  15. Thanks a lot of! it saved a lot of time and solved my problems at my new web page! thanx a lot!

  16. Thank you ever so much. Your gift of knowledge keeps on giving. I’ve spent too much time searching for a solution to this and yours was straightforward! Thanks for sharing!

  17. I wanted to thank you for this awesome solution.
    I had the same problem working on a chm help file months ago.
    That time this it solved my problem, BUT now another
    problem emerged out of the HTML bag.
    and that’s when you have to refer to an inline position.
    I mean something like this for example:

    Something and Anything something else . . .

    This work around causes “something else” to be rendered to a new line and
    that’s another problem, that I believe is because of “display:block”.

  18. Sorry for BAD output

    The example was:

    <p>Something and Anything <span id=”my-id”></span>something else . . . </p>

  19. Thanks! This was driving me crazy and your solution is simple and effective. I’d be interested to know what a more “semantic” solution would be, without an empty span, but at this point I’m just happy to have it finally working.

    Thanks again.

  20. Was pulling my hair out with this bug/issue. Thanks for the tip sir !! Worked like a charm.

  21. You saved me with this article. Thanks so much. It worked perfectly. Note for mobile don’t forget to readjust your height for the size of the mobile menu.

  22. If you have the div in a column, change ‘display’ to inline block.
    display: inline-block;

  23. Hello
    Just wanted a say a huge thank you for this, I was beginning to think I would never work this one out without making a big mess. I can go away for Christmas now with a smile on my face, thank you so much.
    Diane

  24. .anchor{
    position:relative;
    display:block;
    top:-3.618em;
    height:0;
    width:0;
    visibility:hidden;
    }

    This will prevent unwanted layout “empty spaces”

  25. The same bug appears when finding a page with Ctrl+F: the found text would be under the header.
    One have to search and then scroll a little bit up to see the highlighted result…
    Did you find a solution for this problem?

  26. Very nice! The only problem I have is when using the CSS :target selector. Now it will affect the invisible span instead of the invisible element. I guess it’s more a Javascript problem now. Good job anyway!

  27. THANK YOU SO MUCH FOR THIS! I am a student new to coding and this saved my butt and easily solved my problem! ( :

  28. Hi there,
    I have a menu item that links to an anchor. When I’m on the same page as the anchor and I click the menu item, it takes me to the place I want and nothing is hidden behind the fixed header. When I’m on a different page, however, and I click the same menu item, I’m taken to the place in the text but the top portion is hidden behind the fixed header. This means that the fix above (and any other fix I can think of) will work correctly if I’m coming from another page, but if I’m coming from the same page it will create a space at the top when I navigate to the anchor. Do you have any idea how to fix this?

  29. You are Superb !!! … .. Exactly 100% right what people says… It’s Works.. !.. Thanks A lots….. This had cause me headache for quite long time & now your solution is perfect & Excellent.. !

  30. Excellent and elegant solution – I was looking for the same thing, as I am doing a lot of one page templates with fixed headers – a big thanks from me as well!!!

  31. Works well! I used this to globally set anchors purely used as anchor points (have id but no href):

    a[id]:not([href]) {

    }

  32. Ok i think i would love to say Thaaaaaaaaaaaaaanks. My client was eating my brain (like zombie) because of this issue.

  33. This is a great solution. One issue, what if you only want to use the ID Anchor for mobile devices? Thanks!

  34. Sorry, didn’t work straight out of the box, have a feeling its conflicting somewhere, I did not change any of your variables, simply placed the css in my css file, and the span tags above the section i wanted to anchor to, and when i clicked the menu item, the page just scrolled to the top. I can see this as a great solution, however it did not work for me :/

  35. Works perfectly!
    After days of nothing a step forward thanks your advice! Thanks a million!!!!
    Tried with IE11, Firefox, Chrome, in a pc, and in Firefox, Opera, and Safari in a Mac : It’s work on all of them!

  36. This screws up layout in firefox 41. It’s like it applied the negative margin to the parent element. Works in Chrome.

  37. Hi, I have tried this, but did’t work for me. When I click on the hyperlink ‘link’ e.g. ‘Partners’ to jump to the partner section, the “#partner” hashtag is added to the URL but the page does not load, I then click on the refresh button in the browser (chrome) and it loads. need some help. thank you.

  38. THANKS!!!! So simple… Also to make different on mobile you could add something like
    @media only screen and (max-width: 700px){
    .anchor{
    display: block;
    height: 80px; /*same height as header*/
    margin-top: -80px; /*same height as header*/
    visibility: hidden;
    }
    }
    See the result at my site @ http://sharkt.ca/services/local-seo-canada/ I’m currently doing a mobile version of my site so whit this CSS on top i get the exact result I want. THX a million time.

  39. Thank you so much! My anchor links kept being hidden by the top fixed navigation areas, this was a perfect solution! You saved me HOURS!!

  40. Did not work for me. I have vw values for basically everything. I can’t make the margin-top pull the span up, so it leaves extra space.

  41. Hi thank you for this. But it is not working for me. I am using the CSS editor within wordpress.org. I am wondering if that is having an effect? Let me know if you have any ideas

  42. Hi why not trying:

    #myanchor {
    padding-top: 100px /* height of header */
    margin-top: -100px
    }

    It works great on my pages
    regards peter

  43. I have a problem that I have the half fixed jejeje the anchor works perfectly as the way you helped us but…. It doesnt math when you put on the menu the #section… it does the same problem at the beggining, if you check my website you can discover what i am talking about, press “uno” in the menu at the top… but dont scroll down and you will see… but if you scroll down a bit and the you press “uno”it will match perfectly… do you know why?

  44. Thanks! This worked great and only took a few media queries for all-device perfect viewing. :)

  45. I managed to make it work without span and ID….just adding a class “anchor” to the anchor name.

  46. Terrific solution, thank you!!

    To state the obvious, setting height/margin top at a value greater than that of the nav bar creates even more space. Love the simple customization.

  47. Awesome fix! Super quick and easy to implement. Saved me a lot of headache on my site.

  48. This fix works without aditing any content on your pages:

    :target:before {
    content:””;
    display:block;
    height:90px; /* fixed header height*/
    margin:-90px 0 0; /* negative fixed header height */
    }

  49. hi,
    it working not for the top anker. My menu is not working. I have scroll down a little, after that the menu works. If i go back to top it stops working again…
    any solutions?

  50. Many thanks to @caos ! Your CSS solves my problem.

    caos says:
    January 29, 2015 at 2:01 pm
    .anchor{
    position:relative;
    display:block;
    top:-3.618em;
    height:0;
    width:0;
    visibility:hidden;
    }

    This will prevent unwanted layout “empty spaces”

  51. :target:before {
    content:””;
    display:block;
    height:55px; /* fixed header height your height*/
    margin:1px 0 0; /* negative fixed header height */
    }

  52. Thanks so much. I’m just learning, and I couldn’t find any solutions that I actually understood.

  53. So, I this solution didn’t work for me… I am trying to find a solution where it doesn’t matter how tall the “fixed” element is but that the section always appears underneath it. I say this because this menu is expandable and will change heights based on different window sizes.

  54. Work great ! But one doubt regarding SEO. As anchor links are very usefull to give strength to the keyword used. would it be harmful for SEO to put the anchor on the wrong element (element above the position the anchor should be) ?
    Would be even better to use a trick to be able to keep the anchor position…

    I used your trick on my website.

    NB: in my case i had to adjust the sized of the invisible span to the screen (desktop or smartphone), and also to add an extra margin to the header (only once become sticky – as the relative position on the page move as well…)

    https://thailandfightgear.fr/questions-reponses-faq

  55. Nice!
    On page links lining up nicely allowing for my header.
    Thank you for sharing your solution.

    Jack

  56. today’s best solution is by adding this to CSS:

    :target:before {
    content:””;
    display:block;
    height:60px; /* fixed header height*/
    margin:-60px 0 0; /* negative fixed header height */
    }

  57. WOW! I spent way too long looking for an answer to this, and this was so simple! Thank you!

  58. Although, I came here looking for a different problem: I’m building a nav-bar of anchor links that should stick on left of my page id desktop view. Problem is that when I use position:fixed (or absolute), links become unclickable. Have you seen this problem too?

  59. Thank you so much for this simple solution! In a wordpress theme using themefusion – I added your .anchor css code to the code section of the page, then created a menu anchor element calling the CSS class: anchor. Then fiddle with the header sizing (mine was closer to 310px) – worked a charm!

  60. THANK YOU so very much!! I was going nuts, I have tried for two days(!) with all sorts of weird scroll oriented javascript that didn’t work at all.

  61. Brilliant. Exactly what I was looking for after fixing my header.

    7 years after the original post and still helping people. :-)

  62. I appreciate, result in I found just what I was having a look for.
    You’ve ended my four day lengthy hunt! God Bless you man.
    Have a nice day. Bye

  63. Thank you very much .
    I am a chinese web developers , I’m searching to many websites to find these solution with out JS.
    In my opinion, your solution is the best !

  64. 11 years later and still working. ;-)

    Other solutions are all JS based.
    This took some editing of the HTML but in the end its the only true CSS “only” one I could find out there.

    THANKS!!!

Leave a Comment

Your email address will not be published. Required fields are marked *

To respond on your own website, enter the URL of your response which should contain a link to this post's permalink URL. Your response will then appear (possibly after moderation) on this page. Want to update or remove your response? Update or delete your post and re-enter your post's URL again. (Find out more about Webmentions.)