jQuery: Smooth Scrolling Internal Anchor Links

Here’s a neat little jQuery trick to fancy up your internal anchor links, by making them scroll smoothly to their target as opposed to jumping instantly.

Internal anchor links are very common place,
e.g. “back to top” links, or FAQ pages which list all the questions at the top.
Making them visually scroll to their target not only looks a bit fancy, it also gives some visual feedback to the user as to their new position on the page.

This is what it looks like in action, click the following link:
Scroll to comments

This technique is very simple.

  1. Set up your link as you normally would,
    e.g. href=”#comments” (where comments is the id of your target)
  2. Add a class=”scroll” attribute to the link element, so it now looks something like this:

    <a href="#comments" class="scroll">Scroll to comments</a>
  3. Finally add the following jQuery code wherever is most appropriate

    jQuery(document).ready(function($) {
    		$('html,body').animate({scrollTop:$(this.hash).offset().top}, 500);

And that’s all there is to it πŸ™‚

A common mistake in implementing this script is using “named anchors” for your target, instead of an id attribute on your target element. If you are stuck with named anchors for whatever reason (e.g. due to WYSIWYG restrictions) then you can try this modification from Giles:

$('html,body').animate({scrollTop:$('[name="'+this.hash.substring(1)+'"]').offset().top}, 500);

66 Responses to “jQuery: Smooth Scrolling Internal Anchor Links”

  1. The script gets stuck on the second anchor… what gives? http://felixdeportu.com/ver/6/test2.html

    • Hey Felix – thanks for visiting!
      I’m not sure exactly what behaviour you’re trying to achieve on your test page.
      This script is to add vertical animation to anchor links that were already working.
      You’ll need to include the script with no modifications, add the “scroll” class to the link elements then I’m sure you’ll find it works sweet.

  2. Thank you so much!! This script was so simple and woks so nicely. So appreciated!

    • You’re welcome Drea πŸ™‚

  3. what about if you want it to scroll horizontally? is it the same code?

    • Hi Stelios, thanks for your comment.
      For horizontal scrolling the code is slightly different because you need to use scrollLeft and offset().left.

      Replace the animate line as follows:
      $(‘html,body’).animate({scrollLeft:$(this.hash).offset().left}, 500);

  4. I know how to use internal anchors, but I’ve never used jQuery before. ..Where do I paste the jQuery code? Can I put it in the html of my website somewhere? Or does it need to go in a separate javascript file?

    • Hi Aly – thanks for visiting!
      Firstly you need to load the jQuery core on your page, then you can add jQuery scripts.

      I’d recommend loading the core from Google’s CDN by adding the following script tag to your HTML:

      <script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js'></script>

      Then you can either put the jQuery code in a separate file (e.g. script.js) and include it as follows:

      <script type='text/javascript' src='script.js'></script>

      Or you can put the code directly inside a script element

      <script type='text/javascript'>
      // paste the code here

      Hope that helps!

  5. Hey, thank you, much appreciated. This is exactly what I was looking for. I am glad people like you out there take the time to create these tutorials.

  6. This is so easy to implement, thanks Charlie. πŸ™‚

  7. Thanks a lot bro..
    This is so short and nice!! Works great!! πŸ™‚

  8. nice. thanks

  9. Hi there-

    Thanks for the script, its the simplest and smoothest anchor scroll ive come across so far, and ive been searching for the better part of 2 days…

    I have 2 questions though:

    1. Like Felix above, the script seems to get stuck on the second anchor, and wont scroll back up. The rest of the anchors (ive got 9 on my page) seem to scroll fine… is there something im doing wrong? script was copied and pasted as above.

    2. I was wondering, is possible to get the scroll to stop in the middle of the page, rather than at the top? More precisely, i want the scroll to stop 150px off the top of the browser window. Is this difficult to implement??

    Thanks in advance

    • Hi Mike – thanks for commenting..
      I’m not sure about getting stuck on your second anchor.. I’d suggest installing Firebug to see if any errors are being thrown..

      For your second question – no probs, just use this line:
      $(β€˜html,body’).animate({scrollTop:$(this.hash).offset().top – 150}, 500);

  10. hey charlie,

    I have a fixed navigation set up in my website, but I cant get to the smooth scroll effect to work. What am I doing wrong here?


    • Hi Gabe – this is a common problem πŸ™‚ You need to use id’s instead of name attributes in your target anchors..

  11. Can’t get it to work. As far as I can tell, I have followed the instructions. The anchor links work as expected without the jquery but the navigation breaks when I add the jquery function and add the scroll class to my anchor links. I am using the latest version of jquery, “jquery-1.6.4.min.js”.

    Here is a link to my file: http://www.markhannondesign.com/scrollTest/scroll.html

    Thanks for any help.

    • Hi Mark – thanks for your comment.. You need to use id’s instead of name attributes in your target anchors..

  12. Thank you for this wonderful snippet πŸ™‚

  13. I was looking everywhere for a page scroll. I already had my hashes setup and I was trying different tutorials from other websites, but it wasn’t working. This worked perfect on the first try! Thank you so much for taking the time to put this up for developers.

  14. It works for me. The script is very useful and simple. Thank a lot!

  15. If you are using progressive enhancement, you will be scrolling to an anchor tag. Sometimes these have name attributes, rather than ids. In that case, you need the following formulation (note that the selector for the clicked element is also different here, but any valid selector works):

    $(‘ul.toc a’).click(function(event) {
    $(‘html’).animate({scrollTop:$(‘[name=”‘+this.hash.substring(1)+'”]’).offset().top}, 500);

    • Hi Giles – there’s been a few comments from people using named anchors so many thanks for your solution!

      It is worth mentioning that you should avoid using named anchors as they deprecated in XHTML and invalid in HTML5..
      If possible, for internal links you should be using an id attribute on your target element (which should only be an anchor tag if it’s a link itself).

  16. This has literally made my day. Thank you! πŸ™‚

  17. Hi, the jquery works great if there is an anchor with an ID. Our WYSIWYG editor doesn’t create an ID to anchor to, it only creates a name. Can your script be modified to look for the name? Thank you.

    • Hi Steve – thanks for your comment!
      I’ve added a note to the main article above regarding “named anchors”. It contains a modification you can try πŸ™‚

      • Thanks for the updated script. I appreciate it.

  18. thank you so much for the scrolling code. i made a responsive site for tanvenient.com, but on a full screen the main image fills the screen. turns out that novice web users wanted to click the image to get to the site. now, if they click the image, they get a nice smooth scrolling effect to the main content. again, thank you so much for the code and help. –chris

  19. Great script! Thanks!

  20. Thanks man, really big help.

  21. Hello! Thank you very much for that code!

    But I have a liitle issue here : I’d like the scrolled element not to bump the top of the page, i’d like to offset the destination point of the scroll. I’d like to be 100-200px under the top of the page. How can I do that?

    Thnaks a lot

    • Hi David – you’re welcome! You can do this easily by subtracting the desired number of pixels from the scrollTop value..
      $(‘html,body’).animate({scrollTop:$(this.hash).offset().top – 100}, 500);
      $(‘html,body’).animate({scrollTop:$(this.hash).offset().top – 200}, 500);

  22. Hello Charlie,

    script looks great and exactly hat I was looking for, but I have some issues trying to horizontally scroll through a 4000px width table which has 4 1000px width content blocks and where I want to scroll to the 4 different anchors with your script by clicking on the respective navigation links. I have of course changed the code for horizontal scrolling as mentioned before in one of your comments but still having problems.

    Could you PLEASE have a look at the site and see if you see my mistake ?


    Thx in advance for any help !

    • Hi Patrick – thanks for your comment!
      There’s a couple of quick things that I noticed..

      1. You have spaces in your hashes so they don’t match the respective IDs,
      e.g. href=”#section 1″ should be href=”#section1″

      2. Your CSS isn’t quite right with the overflow:hidden.. Take that out and you’ll see some scrolling at least..

      Good luck πŸ™‚

  23. Everyone seems to be having no problems with this, but it isn’t working for me? In fact, it is breaking my link so it doesn’t even work at all. What am I doing wrong?

    Link is at the bottom of the page: http://ericanton.net/mobile

    • Hi Eric – thanks for your comment.. Your “#top” link needs to point at an id=”top” attribute (not a name=”top”)..

      • O wow. Thanks!

  24. Perfect! The script is small and perfect!

  25. Hi there,

    Great script! Just wondering if we could scroll from bottom to the top instead of top to bottom?

    Thanks for your help!

    • Hey Wiro – thanks for your question.. Yep this script will work in any vertical direction. Have fun πŸ™‚

      • Hey Charlie, thanks man such a quick reply πŸ˜€ cheers!

  26. This looks great! Could it be made to work in the following situation?

    Because my links contain s and s are not allowed in As, my “links” are s with onClick=”location.href=’#foo'”

    I was hoping I could just add class=”scroll” to the but that didn’t do anything.

    • Oops, that didn’t look good. Let me remove the angle brackets:

      Because my links contain DIVs and DIVs are not allowed in As, my β€œlinks” are LIs with onClick=”location.href=’#foo’”

      I was hoping I could just add class=”scroll” to the LI but that didn’t do anything.

      • Hey John – thanks for your comment.. Problem is that the script is looking for this.hash which comes from the href attribute of the a tag..
        It’s a bit of a hack but you add a title attribute to your li tags, and use that to specify your target..

        <li class="scroll" title="#foo">

        (You’ll need to lose the onClick attribute)

        Then in the script, just replace this.hash with this.title

        Let me know how you get on πŸ™‚

  27. OK. I’ll try that.

    Must the attribute be “title”? Could it be, say, “target”?

    Maybe you’ll say, yes it could be “target” but then the HTML wouldn’t validate.

    Or maybe you’ll say, no it can’t because what follows the period in “this.” must be something already specified in JQuery.

    Either way, even if I need to use .title, I should be OK. I’m not using “title” for anything else.

    I’ll try it and let you know. Thanks.

    • .title worked fine.

  28. I know this is an older post, but I just wanted to say, thanks! This script, and your instructions, helped me quite a bit on a simple one-page site I put together.

  29. Explained well and works as is for me. Didn’t expect the jQuery to be so light-weight for a vertical scroll effect.

  30. Why is the selector ‘html,body’ instead of just one of those? A result is that the animation runs twice.

    I noticed this because a callback was running twice, which caused problems.


    • Hey John – this is just to get good cross browser support.. I can’t remember which right now but ‘html’ works in some browsers and ‘body’ works in others so specifying both makes it work everywhere.. Doesn’t seem to be a problem if the callback runs twice when used in this case.

  31. Great piece of code Charlie! Sure beats using a whole plugin πŸ™‚

    • Thanks Paul – short and sweet πŸ™‚

  32. How does one dequeue a scroll? I have a DIV inside another DIV. Clicking either triggers the softscroll. But that means clicking the inner one generates two scrolls, first for the inner, then for the outer. Is there a way to either delete the outer from the queue, or stop it from getting queued in the first place? Basically, I want a click on the inner to override a click on the outer. Suggestions appreciated.

    I still love the scroll. Thanks for it!

    • I’ve put $(‘body,html’).clearQueue(); in the animate’s callback function and it seems to work. Is that the right thing to do?

  33. whoa! I been looking and reading a lot of tutorials for this trick and you’re the only who made it very simple to understand for a newbie like me. Thank you so much. you save me from headache x)

  34. Thanks Charlie, great and simple stuff. Works perfect with easing plug-in.

  35. Hi! I absolutely love this script and it is working wonderfully for me! I tried a bunch of other scripts but this was the only one to work! I was also having the issue where it stops at the second anchor and I figured out the issue: if, in your css file, you have overflow:hidden to hide the scrollbar on the right hand side, it stops. As soon as I took that line out, it goes anywhere on the page. Hope this helps someone!

  36. If I could find you, I would kiss you. I’ve been pulling my hair out, but this worked like a charm. THANK YOU.

  37. Small, simple and works across all devices and browsers. Perfect. Thank you very much.

  38. Very nice and handy script worked for me well.

  39. First item I found with a search and it was just what I needed. Done in about 5 minutes. Thanks.

  40. thanks,

    works like a charm… πŸ™‚

  41. amazing stuff! Thank you so much!

  42. Been looking for a tutorial on this for ages, thank you!

  43. Fantastic script. When things are made so simple they have to be the way to go. Definitely.

    Great job!!

  44. Thats a super cool and useful snippet Charlie, thanks a lot! =3