A few of my favourite blogs have this feature: a sticky sidebar navigation.

It allows user to quickly navigate to section of the article they're interested in.

Some examples:

ahrefs-demo

Source: https://ahrefs.com/blog/seo-checklist/

sitebuilderreport-demo

Source: https://www.sitebuilderreport.com/squarespace-review

Today we're going to create a mash up of these two using HTML, CSS, Javascript and Bulma.

The final result we're expecting

final-result

Since this post is about creating sticky sidebar navigation, I don't want to spend too much time creating the layout of the page, so Bulma is going to help with that.

For those who might not know, Bulma is a CSS framework that has a lot of built-in components to help us quickly create layouts and web elements that are commonly used.

First off, we're going to create this layout.

create-this-layout

Creating a 3 column layout with Bulma

Creating a 3 column layout with a hero top section is fairly simple with Bulma.

You basically add pre-defined CSS classes to HTML tags (eg: div, h1, h2 etc) and you can achieve the desired result.

If I add a container class (from Bulma) on a div, this div will act as a container with a max width that will be always centered on desktop.

Similarly, if I want to create a hero section, there's a hero class for that.

And if I want to create a 3 column layout, I would just need to write something like this:

<!-- columns is a container class-->
<div class="columns">

<!-- Can add as many column as you want-->
    <div class="column">Content 1</div>
    <div class="column">Content 2</div>
    <div class="column">Content 3</div>
</div

This however, will create 3 columns of equal size. If we want to create a layout like Ahref's blog where the content (middle column) takes the majority of the real estate, we would have something like this:

<!-- columns is a container class-->
<div class="columns">

<!-- Can add as many column as you want-->
    <div class="column">Content 1</div>
    <div class="column is-half">Content 2</div>
    <div class="column">Content 3</div>
</div

Notice the is-half class. This tells the div to take up 50% of the width available. There are more sizes which you can use, such as: one-third, two-thirds, one-quarter etc which are documented here.

Once you have created the hero section and the 3 column layout, just fill in the rest of the page with arbitrary content and anchor links in the sidebar.

Here's the HTML code in full:


<!-- index.html -->

<!DOCTYPE html>
<html>
<head>
	<title></title>
	<link rel="stylesheet" type="text/css" href="css/bulma.css">
	<link rel="stylesheet" type="text/css" href="css/main.css">

</head>
<body>
	<div class="container">
		<div class="hero-body">
   			 <div class="container has-text-centered">
     		 <h1 class="title"> The definitive SEO Checklist for 2018 </h1>
      		<h2 class="subtitle">David Nge | January 6, 2019, | 3 comments</h2>
    </div>
  </div>
		<div id="here" class="columns">
			<div class="column">
				<div class="menu sticky">				
					<p  class="menu-label"><b>Quick Links</b></p>
					<ul id="menu" class="menu-list">
						<li><a href="#basic">Basic SEO Checklist</a></li>
						<li><a href="#keyword">Keyword Research Checklist</a></li>
						<li><a href="#onpage">On-Page SEO Checklist</a></li>
						<li><a href="#content">Content Checklist</a></li>
						<li><a href="#technical">Technical SEO Checklist</a></li>
						<li><a href="#link">Link Building Checklist</a></li>
					</ul>
				</div>
			</div>
			<div class="column is-half content">

				<h2 id="basic" class="title is-3">Basic SEO checklist</h2>

				<p>Lorem ipsum....</p>

				<h2 id="keyword" class="title is-3">Keyword Research Checklist</h2>
				<p>Lorem ipsum....</p>

				<h2 id="onpage" class="title is-3">On-Page SEO Checklist</h2>

				<p>Lorem ipsum....</p>

				<h2 id="content" class="title is-3">Content Checklist</h2>

				<p>Lorem ipsum....</p>

				<h2 id="technical" class="title is-3">Technical SEO Checklist</h2>

				<p>Lorem ipsum....</p>

				<h2 id="link" class="title is-3">Link Building Checklist</h2>

				<p>Lorem ipsum....</p>

			</div>
			<div class="column">
				<h3>David Nge</h3>
				<p>Lorem ipsum....</p>
			</div>
		</div>
	</div> <!-- end container -->
		<script src="js/main.js"></script>

</body>
</html>

A couple of notes:

  1. This html assumes you have the following folder structure:

Project folder (folder)
index.html
css (folder)
main.css
bulma.css
js (folder)
main.js

  1. You need to download bulma and place it in your css folder

  2. I'm shortening the lorem ipsum text on purpose, you should generate more more lorem ipsum text to really see the sibebar navigation in action.

  3. You might need to read some documentation for formating menu items, content, and the hero section which are used in the HTML above.

  4. The id you defined in the content section inside h2 should be the same as the navigation link.

So if you have a <h2 id="basic">Basic SEO checklist</h2>

your navigation link should be

<li><a href="#basic">Basic SEO Checklist</a></li>

Once you have everything in place you'll have have something like this:

demo-html-completed

You should be able to click on the navigation links on the sidebar, and it'll take you to different section of the page.

local-after-html

Making the sidebar navigation sticky

Believe it or not, making the sidebar navigation sticky is as simple as adding a class to the sidebar container:

<div class="menu sticky">
</div>

and in your main.css:

.sticky	{
	position: sticky;
  	top: 30px;
}

Now your sidebar navigation is sticky:

sticky-menu-html

The next thing you want to do is to make the page scrollable whenever you click on your navigation link:

/** main.css **/
html {
	scroll-behavior: smooth
}

highlight-when-clicked
To achieve this, we'll need this piece of Javascript:


//locate all the navigation links
var quickLinks = document.querySelectorAll(".menu-list a");

for (var i=0; i<quickLinks.length; i++){
	quickLinks[i].addEventListener('click', function(event){
        
        //check if a link is currently selected, remove is-active class if yes
		isActive = document.getElementsByClassName('is-active')[0];

		if (isActive != undefined){
			isActive.classList.remove('is-active');
		}
        
        //then add is-active class to the most recent selected link
		this.classList.add('is-active');
	
	});

}

Let me explain:

First, we locate all the navigation links and put them in an array called quickLinks.

Then for each of the nav link we'll add a event listener for click event. Basically whenever one of this links is clicked something will happen.

In this case we're going to add the class is-active to the link. The class is a pre-defined class from Bulma that highlights the menu item (nav link) when it is selected.

But we also have to account for previous selected link by removing the is-active class from them, otherwise every selected link will be highlighted.

Highlight navigation link while you scroll

Everything's cool up till this point. User can select a link and quickly navigate to that section with nav link highlighted, which indicate where we are on the page.

We're going to take this one step further.

We want the user to know which section of the page they're reading while they scroll.

highlight-when-scroll

First, we need to find out the position for each section on the page.

for (var i=0; i<quickLinks.length; i++){

//This creates an array of ids, expected output is ["basic", "keyword", "onpage", "content", "technical", "link"]
hashArray.push(quickLinks[i].href.substring(quickLinks[i].href.indexOf('#')+1));
}

//This creates an array of position for each of the IDs identified above
for (var i=0; i<hashArray.length; i++){
	positionArray.push(document.getElementById(hashArray[i]).getBoundingClientRect().top);
}

Then we'll add an event listener for scroll. Whenever the user is scrolling the page, it'll check which position is the current scroll position in.

If the current scroll position is in between the current section and the next, then apply the is-active class to this section's navigation link, which will highlight it in blue.

This tells the user which section of the page they're reading.


document.addEventListener("scroll", scrollHandler, true);

function scrollHandler() {

	currentScrollPosition = document.documentElement.scrollTop;	

	for (var i=1; i<=positionArray.length; i++){

		if (currentScrollPosition>=positionArray[i-1] && currentScrollPosition < positionArray[i]) {

			var currentActive = document.getElementsByClassName('is-active')[0];

				if (currentActive != undefined){
			currentActive.classList.remove('is-active');
		}
			
			quickLinks[i-1].classList.add('is-active');

			break;

		}

		if (currentScrollPosition>positionArray[positionArray.length-1]){
			var currentActive = document.getElementsByClassName('is-active');


				var currentActive = document.getElementsByClassName('is-active')[0];

				if (currentActive != undefined){
			currentActive.classList.remove('is-active');
			}
			quickLinks[quickLinks.length-1].classList.add('is-active');

			break;

		}
	}
};

With this your page should now have a sticky navigation bar and the ability to tell which section user are reading as they scroll through the page.

But there's still one minor thing we need to sort out.

Now whenever you click on a navigation link, it will highlight all of the previous links before it gets to the one you clicked, creating some sort of a delay action.

delay-scroll-highlight

This is because we implemented a scroll event listener. Whenever you click on a nav link, the page is scrolled.

And when the page is scrolled, the scrollHandler function will be triggered, which highlights all of the sections that we scroll past when we first click on the navigation link.

In order to achieve the effect we want, we need to temporarily disable the scrollHandler whenever we click on the navigation link.

document.removeEventListener('scroll', scrollHandler, true);

and once the is-active class is added, we will re-enable the scrollHandler.

//re-nable the scrollHandler function 1 second after
setTimeout(function(){
    			document.addEventListener("scroll", scrollHandler, true); 
	}, 1000); 

If you combine this together with the click event code from before, it will now look like this:

for (var i=0; i<quickLinks.length; i++){
	quickLinks[i].addEventListener('click', function(event){
		
        //disable scroll listener after clicking on nav link
        document.removeEventListener('scroll', scrollHandler, true);

		isActive = document.getElementsByClassName('is-active')[0];

		if (isActive != undefined){
			isActive.classList.remove('is-active');
		}

		this.classList.add('is-active');
 	
        //re-enable scroll event 1 second after is-active class is added
		setTimeout(function(){
    			document.addEventListener("scroll", scrollHandler, true); 
	}, 1000); 
	
	});

}

And that's it! You should now have implemented the sticky navigation with scroll highlights.

final-result-1

Don't worry if some of what I wrote doesn't make sense just yet. You can check out the full source code for the project here.

If there's any question feel free to comment in the section below!

I'll see you next time.