Ali Jafarian

Today we’re going to build a responsive scrolling webpage using jQuery and Twitter Bootstrap.

This sort of page is very popular for simpler websites that don’t need deep navigation and/or want to quickly communicate their message. Page scrolling is also an effective way to leverage lots of content on a single page and keep your users engaged while reading. That said, let’s jump in!

The HTML

As usual, we’ll start with our markup. First, we’ll tackle the navigation using a fixed header and some of Bootstrap’s standard .navbar HTML. We’ll assign the class of .scroll-link to all our main nav links, and .scroll-top to our logo.

Then we’ll create .page-section divs and some content for each page section. Each .page-section div that we want to scroll to will have a unique id for styling and targeting (ex: different background images).

Next, we’ll go back and add data-id attributes to all our scroll links. The data-id for each link will be the same id of the page section we want to scroll to.

Note: You can also assign the .scroll-link class and data-id attribute to any links on the page, not just nav links.

<div class="header">
    <div class="container">
        <nav class="navbar" role="navigation">
            <div class="navbar-header">
	        <button type="button" id="nav-toggle" class="navbar-toggle" data-toggle="collapse" data-target="#main-nav">
		    <span class="sr-only">Toggle navigation</span>
		    <span class="icon-bar"></span>
		    <span class="icon-bar"></span>
		    <span class="icon-bar"></span>
	        </button>
	        <a href="#" class="navbar-brand scroll-top">Demo</a>
            </div>
            <!--/.navbar-header-->
	    <div id="main-nav" class="collapse navbar-collapse">
	        <ul class="nav navbar-nav">
                    <li><a href="#" class="scroll-link" data-id="africa">Africa</a></li>
		    <li><a href="#" class="scroll-link" data-id="antarctica">Antarctica</a></li>
		    <li><a href="#" class="scroll-link" data-id="asia">Asia</a></li>
		    <li><a href="#" class="scroll-link" data-id="australia">Australia</a></li>
		    <li><a href="#" class="scroll-link" data-id="europe">Europe</a></li>
		    <li><a href="#" class="scroll-link" data-id="north-america">North America</a></li>
		    <li><a href="#" class="scroll-link" data-id="south-america">South America</a></li>
	        </ul>
	    </div>
	    <!--/#main-nav.navbar-collapse-->
	</nav>
        <!--/.navbar-->
    </div>
    <!--/.container-->
</div>
<!--/.header-->

<div id="africa" class="page-section">
    <div class="container">
	<h2>Africa</h2>
	<p class="caption">...</p>
    </div>
    <!--/.container-->
</div>
<!--/#africa-->

<div id="antarctica" class="page-section">
    <div class="container">
	<h2>Antarctica</h2>
	<p class="caption">...</p>
    </div>
    <!--/.container-->
</div>
<!--/#antarctica-->

<div id="asia" class="page-section">
    <div class="container">
	<h2>Asia</h2>
	<p class="caption">...</p>
    </div>
    <!--/.container-->
</div>
<!--/#asia-->

<div id="australia" class="page-section">
    <div class="container">
	<h2>Australia</h2>
	<p class="caption">...</p>
    </div>
    <!--/.container-->
</div>
<!--/#australia-->

<div id="europe" class="page-section">
    <div class="container">
	<h2>Europe</h2>
	<p class="caption">...</p>
    </div>
    <!--/.container-->
</div>
<!--/#europe-->

<div id="north-america" class="page-section">
    <div class="container">
	<h2>North America</h2>
	<p class="caption">...</p>
    </div>
    <!--/.container-->
</div>
<!--/#north-america-->

<div id="south-america" class="page-section">
    <div class="container">
	<h2>South America</h2>
	<p class="caption">...</p>
    </div>
    <!--/.container-->
</div>
<!--/#south-america-->

The CSS

Luckily, Bootstrap provides default styling for the responsive navigation, so have minimal header styling to do. We will add some simple CSS for the page sections and typography, but nothing crazy.

.header {
	position: fixed;
	width: 100%;
	background: #222;
	z-index: 10;
}
.header .navbar-brand {
	font-weight: 900;
}
.header .navbar {
	margin: 0;
	border: none;
}
.page-section {
	width: 100%;
	min-height: 800px;
	padding: 50px 0;
	border-bottom: 10px solid #fff;
}
.page-section h1 {
	font-size: 4em;
	margin: 50px 0;
}
.page-section h1 span {
	font-weight: 200;
}
.page-section h2 {
	font-size: 3em;
	font-weight: 900;
	color: #fff;
	margin: 0 0 30px;
	text-shadow: 2px 2px 2px #000;
}
.page-section p {
	font-size: 1.2em;
	font-weight: 200;
	margin: 0 25% 20px 0;
}
.page-section p.lead {
	font-size: 1.8em;
}
.page-section p.caption {
	color: #fff;
	padding: 20px;
	background: url(images/trans_black_25.png);
	text-shadow: 1px 1px 1px #000;
}
.page-section#africa {
	background: url(images/africa.jpg) bottom center no-repeat;
}
.page-section#antarctica {
	background: url(images/antarctica.jpg) bottom center no-repeat;
}
.page-section#asia {
	background: url(images/asia.jpg) top center no-repeat;
}
.page-section#australia {
	background: url(images/australia.jpg) top center no-repeat;
}
.page-section#europe {
	background: url(images/europe.jpg) top center no-repeat;
}
.page-section#north-america {
	background: url(images/north-america.jpg) top center no-repeat;
}
.page-section#south-america {
	background: url(images/south-america.jpg) top center no-repeat;
}

@media (min-width: 768px) {
	.header .navbar-brand {
		padding-left: 0;
	}
	.navbar-nav {
		float: right;
	}
}
@media (max-width: 480px) {
	.page-section h1 {
		font-size: 3em;
	}
	.page-section h2 {
		font-size: 2em;
	}
	.page-section p {
		font-size: 1em;
		margin: 0 0 20px;
	}
}

The jQuery

Again, Bootstrap takes care of the responsive navigation toggling, so most of our focus is on the actual page scrolling. We’ll create a scrollToID function first, and then call that function any time a .scroll-link or .scroll-top is clicked. The jQuery knows which page section to scroll to based on the data-id attribute assigned to the link. And of course, if .scroll-top links are clicked you’ll scroll right back up to the top.

One last thing… we need to add a little script to help close the menu in mobile views, otherwise the menu would stay open and require manually closing it after scroll. We’ll add a class of .open to detect when the nav is toggled, and then toggle some Bootstrap classes to tell the nav to close when a link is clicked. This is a bit hacky, I admit, so please feel free to sound off in the comments with a better solution πŸ™‚

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" type="text/javascript"></script>
<script src="js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
	// navigation click actions	
	$('.scroll-link').on('click', function(event){
		event.preventDefault();
		var sectionID = $(this).attr("data-id");
		scrollToID('#' + sectionID, 750);
	});
	// scroll to top action
	$('.scroll-top').on('click', function(event) {
		event.preventDefault();
		$('html, body').animate({scrollTop:0}, 'slow'); 		
	});
	// mobile nav toggle
	$('#nav-toggle').on('click', function (event) {
		event.preventDefault();
		$('#main-nav').toggleClass("open");
	});
});
// scroll function
function scrollToID(id, speed){
	var offSet = 50;
	var targetOffset = $(id).offset().top - offSet;
	var mainNav = $('#main-nav');
	$('html,body').animate({scrollTop:targetOffset}, speed);
	if (mainNav.hasClass("open")) {
		mainNav.css("height", "1px").removeClass("in").addClass("collapse");
		mainNav.removeClass("open");
	}
}
if (typeof console === "undefined") {
    console = {
        log: function() { }
    };
}
</script>

Conclusion:

And that’s it! A simple, yet effective way to build a responsive scrolling webpage. There’a a lot of room for creativity with this sort of page, so hopefully it’s a good starting point for you to build something amazing!

Discussion

84 thoughts on “Responsive Page Scrolling with jQuery and Bootstrap”
  1. Great tutorial, thanks much!

    One question though, any idea if it would be possible to implement a way to link from another page and then scroll to one of the divs that have a data-id property?

  2. Superr, thanks mate! it’ll be great if u can explain the javascipt part. i did’nt really understand this part
    if (mainNav.hasClass(“open”)) {
    mainNav.css(“height”, “1px”).removeClass(“in”).addClass(“collapse”);
    mainNav.removeClass(“open”);
    }
    }
    if (typeof console === “undefined”) {
    console = {
    log: function() { }
    };

    1. The mainNav part handles the automatic closing of the menu when in mobile/tablet view. Otherwise the menu stays open after clicking a link. This plays well with Bootstrap’s menu styling/javascript.

      The typeof console code is an internet explorer fix (or course), so don’t worry about that. Just make sure it’s included or the scrolling might not work in IE.

  3. Thanks for the code. I tried to work with html forms inside the p class caption. But this is not possible. The the p class caption seems not to support that (the background is wrong for the form elements). Is there any way to solve this?

    1. Hey Mav,

      Great question! You can definitely use the .navbar-fixed-top Bootstrap class instead (to your point). This would eliminate the need for styling .header to have fixed positioning.

      The only reason I use my own .header class is to over-ride Bootstrap’s classes more easily. For example, I can target .header .navbar instead of having to over-ride .navbar, which would over-ride all .navbar instances. This is super useful if you plan on having more than one .navbar on your site. This also gives you more control in situations where you don’t want to use default Bootstrap styling.

  4. Hi Ali, thanks for your great sharing. the only thing which is bugging me a little bit is why you didn’t add the active class to any of selected navs? was there any issue/bug on that or it is just your preference to have like this? Can you please let me know how I can enable the code to render the active class, as well? once again thanks,

    1. Hi Behrouz,

      Adding an active class to the selected nav links is pretty simple using jQuery. However, if you do this, you also have to change the active link when a user scrolls, which is a bit more work. Perhaps I’ll add that for v2. Thanks for the suggestion.

      1. Was also looking for just this (with active states). Thanks so much for the great demo otherwise!! Very, very helpful and well presented.

  5. Hey Ali, thanks for sharing this. It’s been a great help! I do want to ask though… How would you include the scrollSpy function from Bootstrap? I had scrollSpy working before I added in the smooth scrolling script. But now that smooth scrolling is working, my scrollSpy seems to be in conflict. Any help would be very much appreciated! Thanks!

    1. Hi chichi,

      Glad the code was helpful πŸ™‚ The scrolling shouldn’t affect ScrollSpy… since all it’s doing is enabling the page to scroll to selected targets. I’d have to see your code to help you troubleshoot. Feel free to post the URL and I’ll take a look if I have time.

      1. Hey Ali, thanks a lot for the reply. Appreciate it. I’ll let you know once I’ve published it. I’m still working on some other kinks. Cheers!

  6. I came up with another solution for closing the menu in mobile views when the scroll is activated. I prefer this solution, as it is simple and merely extends Bootstrap’s existing functionality.

    $(‘.nav a’).on(‘click’, function(){

    if ($(document).width() <= 767){

    $(".navbar-toggle").click();

    }

    });

    Basically saying that when a link inside the mobile navbar menu is clicked, then also automatically click the toggle button, which then closes the navbar menu. However, the function will not execute when the document width is greater than or equal to 767, the media breakpoint. This prevents weird behavior in desktop views.

      1. Hello to both Evelyn and thank you so much to Ali

        though and unfortunately, both your solutions fails totally or partially (at least on blackberry OS 10) when it is used this kind of navigation bar
        http://getbootstrap.com/examples/navbar-static-top/

        and the items in the dropdown menu item, are pointing into the same page (anchors / ids)

        Ali solution goes really to the anchor / id, but next fails to re-collapse/close the menu. It only closes/collapses the dropdown list (which in the mobile version of the navigation only makes “longer” the navigation items list, so it shortens but the other [main] items list remains visible and obviously occupies the whole screen, giving the feeling that nothing have happen, bad user experience). Manually clicking the navigation toggle button, the menu closes and you can verify that the page has correctly reached/scrolled to the expected anchor / id

        Evelyn solution instead fails at all, when you click the menu toggle button, the navigation menu appears and when you click on the dropdown menu item, the page doesn’t scroll/goto the selected anchor/id and instead the menu closes/collapses as expected.

        Well :-)) would you like to mix the two solutions?
        πŸ˜€ since together they would act as expected ahahah, sorry, any hint would be welcome.

        Thank you
        R.

        1. Robert, there will always be bugs here and there with tutorials like this. If they were perfect I’d charge for them, but instead I write these tutorials for free to give people like you a head start on how to solve UI problems.

          Furthermore, I don’t spend time testing every browser/OS known to man, especially mobile devices like Blackberry which have a very insignificant market share. If you’d like to buy me a new Blackberry and ship it to me I’d be happy to fix your bug πŸ™‚

          1. Ahah πŸ˜€ nice point!

            You are right and I’ve thanked you

            This is the kind of tutorial I would recommend to everyone!

            Though, I went further and solved the issues.

            It was not matter of BlackBerry OS 10, this won’t work also shrinking the desktop browser.

            I passed the job of toggling the navigation menu to the scrollto functions, smart and effective IMO.

            But your tutorial has been the turn point!

            If you wanna see the test page in action, have a look at http://www.RecuperoDati.biz/nas

            Thank you
            Robert

          2. … πŸ˜‰ about scrollspy, I don’t need it and I’ve “discovered” it this morning

            I’m surfing through bootstrap elements

            It is really because I consider your tutorial some kind of masterpiece which… without such optional, is missing one “piece” πŸ™‚

            Ciao!

          3. P.S. In this exact moment, I’m using the mobile version of your website.

            It has taken many swipes to reach comments and viceversa to go back to top… πŸ˜‰ may I suggest you an option at top, to jump to comments, and one to scrolltotop?

            Especially the second one could be useful with a long comments queue.

            R.

          4. Hello! Thank to tour tutorial, some other hints and myself coding

            I’ve ended up with 99% of what I wanted to realize

            Now my inpage navigation is in the current navbar item! Additionally an temporary one-time bootstrap popover, hints about the goal of that menu!

            If you wanna see the test page, just open the test directory
            http://www.recuperodati.biz/nas/ it would be great to get your opinion.

            Roberto

        2. [SOLVED]
          Since I’m using the scrollto function, I’ve demanded to the scrollto functions the job. So when the scroll is activated, it also closes the navigation menu.

    1. Thanks Evelyn – I liked your suggestion as well. Seems like I must have mistyped something during implementation of Ali’s code. Yours works like a charm!

  7. I would like to return on the scrollSpy. It would make a lot of sense exactly in the demo that you have built :-).
    Great tutorial, but I would say that scrollSpy has, let me say, “forgot” to be implemented.
    Why don’t update the tutorial?
    Thank you for this curiosity
    R.

    1. Robert, if you need scrollSpy so much why don’t YOU implement it? I’ve already done 90% of the work, so it shouldn’t be that hard to add it in, right πŸ™‚

  8. Hi Ali, thanks for sharing! I started working on this today and ran into a problem, I hope you can help me to solve it. Thanks in advance!!

    So I am building my website based off your source files and after styling the classes and uploaded to my ftp, the responsive version did not work on my phone. However, if I resize the browser on a mac/pc, I can see my responsive version is working. After spending some time trying to figure out what’s wrong, I figured that the problem was not on the css nor classes nor js. I uploaded the original demo folder you have to my server and the responsive did not work on my phone as well. Though the responsive version did work on your demo URL. Is there a way I can solve this problem?

    I hope I am explaining clearly above… appreciate for any help!!

      1. Ohhh, yes I did!! Sorry, I am still very new to these responsive sites when it comes to coding.. But many thanks! It works great now!! πŸ™‚ Keep up the good work, love your tutorials πŸ˜€

  9. Thanks for this, works great except I’m having some issues with the toggle script. My Nav code is slightly different;

    Could you point me in the right direction? Thanks!

    Toggle navigation

    2013

    Introduction
    Thanks

  10. Thanks for this, works great except I’m having some issues with the toggle script. My Nav code is slightly different;

    Could you point me in the right direction? Thanks!

    Toggle navigation

    2013

    Introduction
    Thanks

    1. Sorry, discuss has stripped the code in a wierd way. I think there is probably enough classes there to see the difference though…

  11. Thanx for a great tutorial! How would I go about doing this – I wanted to remove all the pics and set the background of each panel to be just a color. That part worked with background-color, but the panels didn’t fill the entire viewing area. I found a solution for that by adding the following to the existing CSS:

    html, body{ height: 100%;} body { position:relative;}

    It basically works, except that content of the panels won’t stay inside the panels anymore – when viewed on anything other than desktop resolution. It goes outside it’s panel and under the next panel.

    The weird thing is that the carousel works with this combination

    container > row > col-md-12 column

    yet anything else doesn’t scale properly. For instance, I added Bootstrap thumbnails code with this

    container > row > col-md-4 column

    and it doesn’t work. Even the regular block of text doesn’t scale properly. Help would be appreciated πŸ™‚

    1. Peter,

      I’d need to see your page to help understand what you’re trying to accomplish, but it sounds like you want each page section to take up the entire screen height/width when scrolled to. If so, you’ll need some additional JavaScript to achieve this.

      For example, on document load [and resize] you’ll need a function to detect the window height – http://stackoverflow.com/questions/7789043/how-can-i-detect-window-size-with-jquery. Store this value in a variable and then assign it to the .page-section height. Do not use html, body{ height: 100%;} body { position:relative;}… that will introduce all kinds of other bugs… trust me πŸ™‚

      As for your carousel, I’d have to see this as well. I have no idea what you’re trying to do there.

      – Ali

  12. So a friend of mine sent me this tutorial to get my thoughts on it, since he’s new to webdev and I’m not, and after skimming through it, I’ve gotta ask… why are you bothering using data-id to specify a target? The href in an anchor tag is literally designed for the exact behavior you’re looking to accomplish, but in a more semantically correct fashion.

    Using the href tag means that if someone middle clicks the link to open it in a new tab, it will correctly open the page and automatically jump to the correct section on page load. Additionally, this would still work even if JavaScript is disabled, or stopped, because it’d simply fall back to the native anchor jump behavior that all browsers support natively. Additionally, search engines like Google understand anchor links like the one I’m describing above, allowing it to link to a section of the page in the Google result, as opposed to just the page. And finally, it’d also save you the added step of having to append a hashtag to the id, since lines 8-9 of your JS would simply be:

    var sectionID = $(this).attr(“href”);
    scrollToID(sectionID, 750);

    I honestly don’t see a single advantage that a data attribute has over an href in this particular situation, and I’m wondering why you chose that approach.

    1. Yury,

      This is mostly a matter of preference – href vs data-id. Either will work, but there are some differences. To your point, the href would be a bit more “semantic” and offer native page linking when used outside of this page scope.

      However, if you use href you can ONLY use anchor tags for your scrolling functionality since they are the only DOM elements with the href property. For example, I may want to use a span or a div in some cases for my scroll-to behavior, in which case the data-id is globally accepted. Furthermore, data attributes are part of the HTML5 spec and are typically more appropriate for “interaction” based behaviors.

      Hopefully that answers your question. Thanks for writing in πŸ™‚

      – Ali

      1. You make an excellent point in that the data attribute is more globally usable.

        As for your point about “interaction” based behaviors though, I’m not arguing that you shouldn’t use data attributes or that they’re not part of the spec. Your use of it is technically 100% correct, but I’m more referring to the appropriateness of its use, if you catch my meaning. Seeing as how in this *very specific particular instance* of user interaction, all you’re really doing is animating a native browser behavior, it would be more correct to perform the action as an extension of the same way method the browser already expects.

        With that said, I’d agree that it’s largely a matter of preference and individual needs on a per project basis. In my opinion the anchor tag approach provides more usefulness for the reasons I mentioned above, but it’s certainly understandable that in some circumstances those points would be moot.

        Thank you for the reply.

  13. Hi Ali, awesome tutorial. I am having one major issue. When I wrap all the content divs in a fluid container (and add the nav id’s to rows), the responsive scrolling stops working entirely. Do you know if there is a way to keep the scrolling and still use the container?

          1. Ok, my first instinct is that you’re using the Bootstrap scrollspy component… this could certainly cause conflicts as it listens for DOM events just like my custom page scrolling script.

            I see your pictures, but unfortunately this isn’t enough context to help you really troubleshoot. I’d need to see a live interactive example to understand what you’re trying to achieve.

            – Ali

    1. Mark,

      That’s actually not a stupid question… given that we’re using Bootstrap for this, centering the menu is not completely straightforward… but it can be done with some over-rides. Try starting with this:

      @media (min-width: 768px) {
      .navbar-nav {float: none; text-align: center;}
      .navbar-nav > li {float: none; display: inline-block;}
      }

      That should get you 90% there πŸ™‚

      And make sure you target those specifically (ex: #header .navbar-nav) otherwise you will over-ride ALL the navbars in your project, which you may not want.

  14. Hi Ali,thanks for this wonderful tut. I’m just wondering, is there a way that we can have a fixed-width for the menu navigation? like 1024.? width: 80%; margin: 0 auto; doesn’t seem to work πŸ™ THANKS!

  15. Hi Ali, thank you for the nice template. I tried it in IE8 and on android 2.3.6 and it doesn’t work. Is there a reason for it? In IE8 I can’t see the navigation items. and on android 2.3.6 the navigation is not fixed. The page is scrolling and the navigation is not visible.

  16. hi Ali thanks for this job.

    i got this error “Uncaught TypeError: Cannot read property ‘top’ of undefined ”

    cause this dose not work with me
    var targetOffset = $(id).offset().top – offSet;

  17. Ali – Firstly thank you zoo much for the work – I’ve just recently come back to web design and I am a bit outta the loop on some things… I have been pulling my hair out to get active class on the nave and was hoping you could point me in the right direction? I can provide you a link if it would be helpful. Thank you for your time & consideration.

    1. Hey Chad, thanks for the kind words. Highlighting the active nav, and keeping it active during user scrolling, is a bit tricky. It requires some JavaScript to detect when the user is within each area of the page… perhaps I’ll write up a tutorial on that instead of trying to explain here πŸ™‚

  18. Hey thanks for this. I had seen some scrolling things on SO, but this one is nice because of the scroll-link class which doesn’t affect my other anchors (ie modal popups)… very nicely done!

  19. Hi Ali, I am facing a problem regarding to background image. I am building a web site where a put a div and applying one background image on that div that site is running good on iPhone 4, 5 but on iPhone 6 the background image disappears on chrome the same image is viewable on same device on safari. Please help to solve this issue below is the css I am using
    .main_div
    {
    background-image: url(“images/img_004-1940px.jpg”);
    background-position: center top;
    background-repeat: no-repeat;
    background-size: cover;

    }

  20. Hey,
    Is there any way to make each nav link class=”active” while scrolling each related page section.

  21. Hello Ali,

    I am using your code, and the scrolling works fine, but now, I have links in my text to external sites e.g facebook/insagram/twitter. These links are now not working.

    I am also getting the following errors in my console:
    Uncaught TypeError: Cannot read property ‘top’ of undefined(…)scrollToID @ sar.js:32
    (anonymous function) @ sar.js:16
    dispatch @ jquery.min.js:3
    r.handle @ jquery.min.js:3

    It is referring to this line of code: var targetOffset = $(id).offset().top – offSet;

    Any idea’s how to fix this?

  22. Hi Ali, Great Demo. Just one issue there, it was better if active menu change with scrolling also. just scrolling not clicking on menu.
    Can you do that please?

Leave a Comment

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