How to Scroll to an Internal Link with jQuery

One page scrolling sites have experienced a huge growth in popularity in web design in recent years. Although this type of site isn’t for everyone, it is still useful to know how they work. Today, I will teach you how to create a very simple one page scrolling site using jQuery.

How to Scroll to Internal Link with jQuery

This is what we will be building:

Scroll to Internal Link with jQuery

OK, lets get on with it…


This page will have very basic HTML – just enough for a navbar and some content.

First off, let’s build the nav.

			<a href="#paragraph1">Paragraph 1</a>
			<a href="#paragraph2">Paragraph 2</a>
			<a href="#paragraph3">Paragraph 3</a>
			<a href="#paragraph4">Paragraph 4</a>
			<a href="#paragraph5">Paragraph 5</a>

Here’s the idea behind this: the “nav” has a width of 100% to be the full width of the browser. This “nav” has the “position” property set to “fixed”, so that it scrolls with the user. We then hav a “ul” inside it to hold the navigation.

Take a look at the links – they all point to a particular paragraph.

This is useful in two ways:

  1. If the user has javascript disabled, the links still work.
  2. Using jQuery, we’ll read the “href” attribute off of each link.

Now that we have a simple navigation bar set up, we can do the main content of the page.

<div id="content">

<p id="paragraph1">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec luctus, dui nec porttitor rhoncus, magna mi adipiscing nisl, at laoreet nisl metus at leo. Maecenas bibendum, nibh ac blandit pharetra, eros tortor pretium lorem, ac posuere lorem leo imperdiet quam. Cras vitae eros libero, vel commodo sapien. Cras mauris dui, vulputate vel adipiscing pellentesque, mattis et ligula. Sed massa mauris, luctus sed feugiat at, bibendum vitae magna. Aenean pellentesque, purus non placerat fermentum, nibh ante posuere leo, eget vehicula nibh elit in elit. Proin aliquet aliquet odio vel auctor. Proin sed augue velit. Phasellus metus mauris, scelerisque vitae tincidunt eget, dignissim nec mi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum eleifend, nisi et congue placerat, purus sem auctor magna, et cursus ante lectus a nulla. Vestibulum tempor, ipsum id congue accumsan, velit mauris rhoncus urna, et accumsan velit orci ac ligula. Vestibulum lobortis facilisis mauris, ut varius mi suscipit in. Donec lobortis diam id nisl tincidunt eget adipiscing mauris vestibulum.
<p id="paragraph2">
In ut sapien sem, a convallis odio. Aenean consequat ornare egestas. Aenean adipiscing magna et ante varius viverra. Nullam hendrerit, augue et porta bibendum, est ante pretium nunc, quis euismod enim dui sed neque. Duis dictum odio quis lacus tempor a hendrerit elit laoreet. Nunc id nisl vel risus rutrum mattis. Sed fringilla ultrices eleifend. Curabitur mi sem, hendrerit et semper gravida, gravida eget ipsum. Ut sit amet magna elit, non viverra ante. Nulla ut lorem risus. Morbi ac iaculis sem. Maecenas accumsan arcu eu nulla aliquet non pharetra risus adipiscing. Suspendisse consequat justo a sapien dictum dapibus. Duis fermentum risus a neque bibendum quis malesuada erat tempus. Nunc sodales hendrerit porta.
<p id="paragraph3">
Donec sodales diam et libero ultrices ornare. Aenean vel justo quis ligula facilisis rutrum ut at ante. Proin vitae vestibulum nisl. Sed lacinia dui aliquet orci sollicitudin in feugiat mi porta. Proin mollis tempor lectus, convallis sollicitudin est iaculis quis. Ut vel turpis et sem auctor suscipit sit amet non augue. Pellentesque pellentesque nisl sed metus consectetur et scelerisque ligula porttitor. Proin luctus luctus turpis quis pellentesque. Duis tempor est eget mi pellentesque pulvinar. Nullam euismod urna a sem faucibus vulputate. Aliquam erat volutpat. 
<p id="paragraph4">
Phasellus dolor sem, pharetra nec scelerisque sit amet, consequat quis dolor. Nullam vitae dui non leo faucibus laoreet nec ut nibh. Nullam eleifend pretium imperdiet. Donec et quam odio. Morbi non sem nunc, iaculis aliquam orci. Curabitur viverra consectetur nisi, eu consequat magna varius non. Aliquam odio lorem, imperdiet congue rutrum quis, lobortis at purus. Fusce placerat tempor arcu, congue bibendum diam sagittis ac. Suspendisse erat elit, sagittis vel lacinia ut, cursus ac velit. Suspendisse consectetur orci sit amet dui consequat quis eleifend nulla luctus.
<p id="paragraph5">
Proin varius pellentesque velit, at consequat risus hendrerit quis. Nam interdum justo sem, quis porta magna. Nunc gravida, libero sed tempor molestie, nisi libero posuere nibh, quis vulputate nibh nibh sit amet nibh. Vivamus vitae erat sed nibh facilisis posuere sed sit amet metus. Quisque hendrerit fringilla elit, id fermentum ante sollicitudin eget. Ut eget arcu id tortor viverra accumsan nec sed dui. Nullam vehicula tortor et quam blandit lobortis. Duis gravida risus sit amet tortor convallis eu feugiat neque consectetur. 


The markup here is very simple. There’s a “content” div that holds the paragraphs, and some “p” tags with IDs corresponding to the order.


Before we do this, make sure to grab Eric Meyer’s CSS reset. This evens out all browser inconsistencies and lets us work without worrying if the design looks the same in all modern browsers.

We’ll style the main content of the page first, since it is the most simple.

body {
font-family: arial;
font-size: 15px;
line-height: 25px;
color: #515151;
background: #fdfdfd;

#content {
width: 500px;
margin: 0 auto;
padding-top: 40px;
height: 2000px;

#content p {
margin-bottom: 25px;

The body has some simple text and background-color styling, and the content has a width of 500px and is centered. The content div also has a padding-top set to 40px – this is so that the navbar doesn’t block the top 40px of the content. The height is set to 2000px so there is enough space for the content to scroll. This isn’t necessary most of the time. Each paragraph has a “margin-bottom” of 25px, so we can tell where one paragraph ends and the other starts.

Now, we can style the navigation:

nav {
width: 100%;
position: fixed;
height: 40px;
background: white;
border: 1px solid #CACACA;
border-top: none;
-webkit-box-shadow: 0px 0px 3px 1px #ebebeb;
-moz-box-shadow: 0px 0px 3px 1px #ebebeb;
box-shadow: 0px 0px 3px 1px #ebebeb;

nav ul {
width: 750px;
margin: 0 auto;

nav ul li{
float: left;
width: 150px;
text-align: center;

nav ul li a {
line-height: 40px;
font-size: 16px;
text-decoration: none;
color: #515151;
border-bottom: 1px dotted #515151;

nav ul li a:hover{
color: #000;

The “nav” has a width of 100% so it takes up the whole browser width. It also has “position:fixed” so that it stays on screen when the user scrolls. The height is set to 40px, which is reasonable size for a top navbar. There’s also some simple styling just to make it look nice.

The “ul” has a width of 750px so there is enough space for each link, and it’s centered. Each “li” is floated to the left so that all the links are on one line. Finally, there’s some simple link styling.

The jQuery

Here’s how this will work: There’s going to be a click function for each nav link, which will then execute a function to scroll to the div the link is pointing to.

As always, start off with a document.ready function.



Now, before we write the click function, we’ll write the “scrollToDiv” function that will (surprisingly) scroll to a div of our selection. There are going to be 2 parameters – the element to scroll to, and the height of the navigation at the top of the page.

function scrollToDiv(element,navheight){


We now declare 3 variables that we need to be able to scroll accurately.

function scrollToDiv(element,navheight){
	var offset = element.offset();
	var offsetTop =;
	var totalScroll = offsetTop-navheight;

The “offset” variable is the offset of the element, and the “offsetTop” variable uses the “offset” variable to withdraw the “top” value. As a result, we get the distance of an element from the top of the page. The “totalScroll” variable is how much the browser should scroll. Without a top navigation bar, the amount to scroll would just be the offset of an element. However, since we have a navigation bar that blocks the top 40px of the content from view, we have to edit the variable accordingly. This is what the “navheight” parameter is for.

Lastly, we scroll the page:

	scrollTop: totalScroll
}, 500);

The jQuery “animate” function can also animate the scrollTop of a page, which allows us to smoothly scroll to a desired spot on the page. Here, the animation takes 500 milliseconds.

Here’s the complete “scrollToDiv” function:

function scrollToDiv(element,navheight){
	var offset = element.offset();
	var offsetTop =;
	var totalScroll = offsetTop-navheight;
			scrollTop: totalScroll
	}, 500);

Now, we can create the click function.

$('nav ul li a').click(function(){

	return false;

This is just the skeleton of a click function, with a “return false” statement at the end so that the browser doesn’t actually follow the link.

Before we can pass an element to the function, we have to find the name of that element.

var el = $(this).attr('href');
var elWrapped = $(el);

The “el” variable is just the value of the “href” attribute. The “elWrapped” wraps the “el” variable so that jQuery can use it. jQuery can’t execute the following code:


…But it can execute this:


That’s the reason the “elWrapped” variable is necessary.

So, here’s the complete “click” function:

$('nav ul li a').click(function(){
	var el = $(this).attr('href');
	var elWrapped = $(el);
	return false;

That’s it – you should now have a simple page with links the make the page scroll.


  • ummm…. I can’t access the demo. the link just brings me back to this page. 

  • Very nice effect! Thanks Alexandre.

  • Pilotrtc

    I really like this solution. I would have loved it if it worked on my iPod Touch.

  • Very nice effect!

  • Wynryder

    Seriously? I had no trouble at all with those sites. Seemed pretty obvious to me – you should get out more.

  • Alexandre Smirnov

    Hello Rich,
    Just as I said in the tutorial, this type of site isn’t for everyone ;)No worries about the rant, it’s nice when people post what they think about a particular subject.- Alexandre

  • Jens Caspari

    Hey Alexandre,  this is a nice one. Unfortunately we have a problem with touch scrolling on the iPad. Maybe you have a solution for the following problem:

    On iPad the first touch on the navigation works like charm, but touching the next link won´t work. Now if I scroll down or up for a pixel or more the scrolling effect works again.

    Doe you have an idea? 

    Thanks in advance,

  • Ljerny

     I was wondering the same thing. I have looked at a number of examples using the scrollTo plugin and they all work the same way on an iPad or iPhone. I’m not sure how it works on an android tablet but I have not been able to get an answer yet. Does anyone have a solution?



  • Skrdkn

    Very Nice

  • Srinivas

    Very helpful article for the serious issue.  Thanks a lot.

  • Benjamin

    Same problem here !!! any solution ? thanks

  • whatever

    Great clean tutorial thanks!

    I would like to use this effect inside a static div in my content rather than as a single page. In other words, i’d like to include this inside an existing page and have the nav hold position while content is in a div that scrolls. Other content on the page unaffected. ANy ideas?

  • hans_landa

    Thanks! Was able to implement it in one of my projects. The tutorial is great but just for your info..the source and demo link did not work for me!

  • I now see that its not necessary to have anything for home button because its a one page design. As for the other links I want to see how to show Bio,portfolio,contact for search engines.I do have ID’s on my bio,portfolio, contact, and the home. I don’t know if I am asking the right questions here. I am still new to web. I am also thank I may not need to show the urls since this is fact a one page site; just with go to links(smooth Scrolling). Thanks for the smooth scrolling script.