<header>
  <h1>Website</h1>
</header>

<nav>
  <ul>
    <li><a href="#section-1">Section 1</a></li>
    <li><a href="#section-2">Section 2</a></li>
    <li><a href="#section-3">Section 3</a></li>
    <li><a href="#section-4">Section 4</a></li>
    <li><a href="#section-5">Section 5</a></li>
    <li><a href="#section-6">Section 6</a></li>
    <li><a href="#section-7">Section 7</a></li>
    <li><a href="#section-8">Section 8</a></li>
    <li><a href="#section-9">Section 9</a></li>
  </ul>
</nav>

<main id="main">
  <section id="section-1">
    <h1>Section 1</h1>
    <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Officiis, blanditiis expedita? Earum eligendi pariatur quaerat quos expedita ab quibusdam ratione veniam in, mollitia fuga repudiandae?</p>
  </section>
  <section id="section-2">
    <h1>Section 2</h1>
    <p>Ratione nulla nam, ipsa dignissimos corrupti veniam nostrum, laudantium asperiores sequi numquam placeat velit voluptate in praesentium non labore unde incidunt laborum maxime quae magni.</p>
  </section>
  <section id="section-3">
    <h1>Section 3</h1>
    <p>Soluta quibusdam ad nostrum vel voluptate delectus sequi dolores quia quaerat officia corrupti, aperiam fugit facere debitis repudiandae praesentium sapiente inventore repellendus, nemo commodi alias!</p>
  </section>
  <section id="section-4">
    <h1>Section 4</h1>
    <p>Aliquid aliquam magnam ducimus similique obcaecati, unde exercitationem laborum incidunt, quas in ipsum inventore nostrum? Blanditiis optio cumque earum iste odio! Alias sint accusamus repudiandae.</p>
  </section>
  <section id="section-5">
    <h1>Section 5</h1>
    <p>Officia ipsum fugit iure eaque quisquam error tempore earum enim illum, delectus officiis incidunt corrupti aliquid nam quas perspiciatis eveniet doloremque quod labore? Doloremque, ipsum?</p>
  </section>
  <section id="section-6">
    <h1>Section 6</h1>
    <p>Aperiam repellat dignissimos fugiat possimus esse, suscipit neque nisi libero alias obcaecati ipsam, porro illo corrupti nostrum reprehenderit unde, illum in laudantium impedit. Modi, veniam.</p>
  </section>
  <section id="section-7">
    <h1>Section 7</h1>
    <p>Cum asperiores temporibus itaque consequatur quod inventore, quia quis explicabo dicta esse minus voluptatem reiciendis eveniet animi, necessitatibus illum dolorem doloremque repellat placeat, dolores eaque.</p>
  </section>
  <section id="section-8">
    <h1>Section 8</h1>
    <p>Optio qui, omnis itaque rerum iusto molestiae necessitatibus deleniti quod tenetur id perspiciatis voluptatum dolorum quisquam eius ipsum non architecto labore! Distinctio, tenetur. Officiis, necessitatibus?</p>
  </section>
  <section id="section-9">
    <h1>Section 9</h1>
    <p>Rem iste iure blanditiis excepturi esse nisi corrupti sequi, illo, laborum quo quis quaerat assumenda perspiciatis quod fuga vel laudantium doloribus architecto tempora omnis earum!</p>
  </section>
</main>

<footer>
  &copy;2018 Footer
</footer>
html {
  scroll-behavior: smooth;
}
body {
  margin: 0;
  display: grid;
  grid-template-columns: min-content 1fr;
  font-family: system-ui, sans-serif;
  
  /* this breaks position sticky in Firefox */
  /* overflow-x: hidden; */
}
header {
  grid-column: 1 / 3;
  background: #455A64;
  color: white;
  padding: 4rem;
  text-align: center;
}
nav {
  white-space: nowrap;
  background: #37474F;
}
nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Only stick if you can fit */
@media (min-height: 300px) {
  nav ul {
    position: sticky;
    top: 0;
  }
}
nav ul li a {
  display: block;
  padding: 0.5rem 1rem;
  color: white;
  text-decoration: none;
}
nav ul li a.current {
  background: black;
}
main {
  padding-bottom: 40rem;
}
section {
  padding: 2rem;
  margin: 0 0 2rem 0;
}
footer {
  grid-column: 1 / 3;
  background: #607D8B;
  padding: 5rem 1rem;
}
let mainNavLinks = document.querySelectorAll("nav ul li a");
let mainSections = document.querySelectorAll("main section");

let lastId;
let cur = [];

// Options to be passe to the observer
const options = {
  root: document.getElementById('#main'), // The "box" we are going to observe, the scroll area
  rootMargin: '0% 0% -80% 0%', // We can modify the margins to only watch some area, in this case: 20% of the top of the box 
  threshold: 0
}
// The observer
const observer = new IntersectionObserver((entries, observer) => {
  
  // Entries are all the items observed which have entered to the scroll area
  entries.forEach(entry => {
    // We only want the ones intersecting wuth our threshold
    if (entry.isIntersecting) {
      // Some magic to map to the link
      let link = document.querySelector('[href="#'+entry.target.id+'"]');
      if (link) {
        // Remove current class from all links
        mainNavLinks.forEach(item => {
          item.classList.remove("current");
        });
        // TODO: Only add if nav ul is "sticky"
        // Add current to new target
        link.classList.add("current");          
      }
    }
  })  
}, options);

// foreach section we send to the observer
mainSections.forEach(target => {
  observer.observe(target);  
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.