Sticky Navigation With ScrollSpy Using Intersection Observer API

Category: Javascript , Menu & Navigation | January 13, 2020
AuthorBramus
Last UpdateJanuary 13, 2020
LicenseMIT
Views4,129 views
Sticky Navigation With ScrollSpy Using Intersection Observer API

This is a sticky on-page navigation (a.k.a table of contents) that automatically highlights the active menu items based on the visibility of their corresponding content sections within the document.

Users are also able to switch between content sections with a smooth scroll effect by clicking the items in the navigation. Heavily based on the Intersection Observer API.

How to use it:

1. Create a list of nav links pointing to the page sections within the document.

<nav class="section-nav">
  <ol>
    <li><a href="#section-1">Section 1</a></li>
    <li><a href="#section-2">Section 2</a></li>
      <ul>
        <li class=""><a href="#section-2-1">Section 2-1</a></li>
        <li class=""><a href="#section-2-2">Section 2-2</a></li>
        <li class=""><a href="#section-2-3">Section 2-3</a></li>
      </ul>
    </li>
    <li><a href="#section-3">Section 3</a></li>
  </ol>
</nav>
<section id="section-1">
  Section 1
</section>
<section id="section-2">
  <section id="section-2-1">
    Section 2-1
  </section>
  <section id="section-2-2">
    Section 2-2
  </section>
  <section id="section-2-3">
    Section 2-3
  </section>
</section>
<section id="section-3">
  Section 3
</section>

2. Enable the smooth scrolling effect.

html {
  scroll-behavior: smooth;
}

3. Make the navigation sticky.

nav {
  position: sticky;
  top: 2rem;
  align-self: start;
}

4. Style the sticky navigation.

.section-nav {
  padding-left: 0;
  border-left: 1px solid #efefef;
}
.section-nav a {
  text-decoration: none;
  display: block;
  padding: .125rem 0;
  color: #ccc;
  transition: all 50ms ease-in-out; 
}
.section-nav a:hover,
.section-nav a:focus {
  color: #666;
}

5. Highlight the active menu items.

.section-nav li.active > a {
  color: #333;
  font-weight: 500;
}

6. The main script to enable the scrollspy.

window.addEventListener('DOMContentLoaded', () => {
	const observer = new IntersectionObserver(entries => {
		entries.forEach(entry => {
			const id = entry.target.getAttribute('id');
			if (entry.intersectionRatio > 0) {
				document.querySelector(`nav li a[href="#${id}"]`).parentElement.classList.add('active');
			} else {
				document.querySelector(`nav li a[href="#${id}"]`).parentElement.classList.remove('active');
			}
		});
	});
	// Track all sections that have an `id` applied
	document.querySelectorAll('section[id]').forEach((section) => {
		observer.observe(section);
	});
	
});

You Might Be Interested In:


Leave a Reply