Dynamic navigation for one-page site with Bootstrap

Everybody knows that people are lazy clicking around, going back etc. so it’s preferred if you can condense all your content and information into one page. It’s trendy even. If you separate the sections of that one page nicely, it can get a smooth feeling of a one-page site, without being too overwhelming for those lazy users.

There might be many different approaches to achieve this, but here I’ll share way – through Bootstrap. Now, why use Bootstrap? Bootstrap provides you not just with a grid system, but also with tons of interactive elements that can help you save time and create an epic looking site in few hours. Besides the grid system, I’m also a huge fan of the way menu items work in Bootstrap. Let’s dive into the details and see what’s so good about it.

A wise man once said “Never memorize something that you can look up.” (Albert Einstein). It’s unnecessary to memorize all the class names and markup for the navigation in Bootstrap. Just jump to the official page and copy it or even better, use my code here:

<header>
    <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#collapse" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#top">Site Logo</a>
            </div><!-- navbar-header -->

            <div class="collapse navbar-collapse" id="collapse">
                <ul class="nav navbar-nav navbar-right">
                    <li class="active"><a href="#home">Home</a></li>
                    <li><a href="#itemone">Item 1</a></li>
                    <li><a href="#itemtwo">Item 2</a></li>
                    <li><a href="#itemthree">Item 3</a></li>
                    <li><a href="#itemfour">Item 4</a></li>
                </ul>
            </div><!-- collapse navbar-collapse -->
        </div><!-- container -->
    </nav>
</header>

Nothing fancy as you can see. We have the part with the HAMburger for the mobile navigation, a navbar-brand for a possible logo and than it’s just the list of the menu items with anchor tags with # signs. Now, further down the page we need an anchor with id corresponding to each of those menu items. For example here is what I did:


<section>
    <h3 id="home">Home section</h3>
</section>

I’ve pimped my sections by giving them 100vh (viewport height) and :nth-child(odd) to be with a darker background. This is only so you can see better the switch between different sections.

The scripts

Now, we can’t do everything just with css, but we also don’t need to add any extra libraries or plugins as we already have Bootstrap and jQuery. What we need to do is activate ScrollSpy, which is a part of Bootstrap, and than we can add two event listeners.
The first event we care about is scrolling smoothly between the page sections after clicking on a menu item. No crazy stuff happens in the url, you can’t neither click back – but why would you need that on a one-page-site?! I didn’t write this code, may be you can read it better than me, but here – get familiar:

$('.navbar 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-topOffset+20}, 500);
			return false;
		}
	}
});

The second event listener we care about, really is a game changer. Through it, we detect when the user has scrolled away from the first section (home) and than we add a custom class to our fixed menu. This custom class changes height, font-size, background-color – whatever you want. The thing is that we have this transition property in there that makes is super sweet and smooth. People will just scroll up and down that point, only for the lulz. Trust me!

$('.navbar-fixed-top').on('activate.bs.scrollspy', function () {

	var hash = $(this).find('li.active a').attr('href');

	if(hash !== '#home') {
		$('header nav').addClass('small-menu')
	} else {
		$('header nav').removeClass('small-menu')
	}
});

One important thing to note is that you need to add your styling in a way that it doesn’t influence the mobile version of the menu.

@media (min-width: 768px) {
... your definition for .small-menu etc.
}

Now, I’m not going to smack any more explanations. Just jump into the code and start exploring and doing your thang. Just note those last lines of script:


var topOffset = 160; // variable for menu height

// Activate ScrollSpy
$('body').scrollspy({
	target: '.navbar-fixed-top',
	offset: topOffset
});

Use topOffset to define how soon or late the next menu item has to be activated in your menu.
Happy coding!

DEMO
DOWNLOAD CODE

Leave a Reply

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