Author: | Bramus |
---|---|
Views Total: | 3,756 views |
Official Page: | Go to website |
Last Update: | January 13, 2020 |
License: | MIT |
Preview:

Description:
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); }); });