Scrolly Nav

Update nav on scroll

by kthornbloom

HTML

<div class="body">
  <nav>
    <ul id="nav"></ul>
  </nav>
  <div class="page">
    <section class="content-section" id="Introduction"><h3>Intro</h3> Set each section with an id for the nav element associated and a class of content-section</section>
    <section class="content-section" id="Materials-and-things">Materials Needed</section>
    <section class="content-section" id="Setup">How to do the setup</section>
    <section class="content-section" id="Step-one">Step One: do the thing</section>
    <section class="content-section" id="Conclusion">The end.</section>
  </div>
</div>

SCSS

.body {
  font-family:sans-serif;
  line-height: 1.3em;
  display: flex;
  height: 100%;
  max-width: 100%;
  width: 100vw;
}
nav {
  background: #eee;
  width: 200px;
  a:link, a:visited {
    display: block;
    padding: 10px;
    width: 100%;
  }
}
.page {
  flex-grow: 1;
  overflow: auto;
  height: 100vh;
}
section {
  border-bottom: 2px solid #ddd;
  padding: 10px;
  height: 100vh;
  z-index:2;
  padding: 30px;
  position: relative;
}

.current {
  background:#bbb;
}

a:link, a:visited {
  color:inherit;
  text-decoration: none;
}

* {
  box-sizing:border-box;
}

h3 {
  font-size: 1.2em;
}

JavaScript

let observerOptions = {
  root: null,
  rootMargin: "50px",
  threshold: .2
};
const imageObserver = new IntersectionObserver((entries, imgObserver) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const currentSection = entry.target
			let sectionIndex = indexInParent(entry.target);
      let currentNav = document.querySelectorAll('#nav li a')[sectionIndex];
      let prevNav = document.querySelectorAll('.current');
      prevNav.forEach((i) => {
      	i.classList.remove('current');
      })
      currentNav.classList.add('current')
    }
  })
}, observerOptions);

// Populate Nav
const arr = document.querySelectorAll('.content-section')
arr.forEach((v) => {
	let navItem = v.getAttribute('id');
   navItem = navItem.replace(/-/g, ' ');
	var node = document.createElement("LI");
  node.innerHTML = '<a href="#'+navItem+'">'+navItem+'</a>';
  document.getElementById("nav").appendChild(node); 
   
  imageObserver.observe(v);
})

function indexInParent(node) {
    var children = node.parentNode.childNodes;
    var num = 0;
    for (var i=0; i<children.length; i++) {
         if (children[i]==node) return num;
         if (children[i].nodeType==1) num++;
    }
    return -1;
}