In-page navigation (offset and active state issues)

Hello,

I’m trying to create a sticky table of content with active state.
I used this tutorial from @aaro .

I’m not a developer and have been scratching my head all morning on two issues:

  1. The table of contents detects the title at the bottom of the page as active state. I would like to highlight the title at the top of the page instead.
  2. In-page navigation scrolls to a heading behind the navigation bar.

I found some threads explaining how to solve the second issue but switching position of header to “fixed” breaks everything and I cannot manage to fix it afterwards.


Navigation issues

Live page : Conditions du dispositif jeune docteur 2021 (upcrown.fr)
Read-only link : https://preview.webflow.com/preview/upcrown?utm_medium=preview_link&utm_source=designer&utm_content=upcrown&preview=5ad94f8f2cf945c521a478ab113f9cbb&pageId=6114ed2a2993b2558769885a&workflow=preview

Thank you for your help!

Hi Joachim!

For the second issue, changing the tag of the nav element to “Header” (see the image) and its position to “Fixed” should do the job.
Screenshot 2021-08-12 at 13.54.55

1 Like

Awesome, I had no idea about the “tag” feature.
It works, I need to learn why but it solved the second issue!
Thank you! :smiley:

For the first one, I understand I’m linking to the heading.
So if the heading is visible, the intersection ratio is 1 and active state is selected.
So I need to actually check when precedent title has left the screen instead of trying to check when next title is in the screen. but how … :face_with_raised_eyebrow:

EDIT 2 : Maybe I should set everything to active, and when it’s not intersecting, remove the active class.

I managed to solve the first issue by setting up the root margin in the code.

Here is the code I used:

<script>
const options = {
  	rootMargin: '0px 0px -80% 0px'
};
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    const id = entry.target.getAttribute("id");
    if (entry.isIntersecting) {
      document.querySelectorAll(".active").forEach((z) => {
        z.classList.remove("active")
      });
      document.querySelector(`a[href="#${id}"]`).classList.add("active");
    }
  });
},options);
</script>
<script>
document.getElementById("content").querySelectorAll("h2,h3,h4").forEach(function(heading, i) { // runs a function for all headings inside your rich text element
  observer.observe(heading);
  heading.setAttribute("id", "toc-" + i); // gives each heading a unique id
  const item = document.createElement("a"); // creates an anchor element called "item" for each heading
  item.innerHTML = heading.innerHTML; // gives each item the text of the corresponding heading
  ("h2,h3,h4").split(",").forEach(function(x) { // runs a function for each item in your headings list
    if (heading.tagName.toLowerCase()==x) {
      item.classList.add("tocitem", "toc-" + x); // gives each item the correct class
    }
  });
  item.setAttribute("href", "#toc-" + i); // gives each item the correct anchor link
  document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div
});
</script>
1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.