Brontes
Brontes

Reputation: 35

Remove class when clicked away

Been struggling with a problem for a few days now. So, when I can't figure it out myself I went to the forum. Hope you guys can help me figure it out.

For the navbar, the items will light up when the user reached the section. That's all good. But when I scroll down and click away the item still lights up. I guess the observer doesn't remove the class. I can't figure out how I could do this.

I made a codepen to illustrate the code and the problem. Hope my question is clear enough.

Thanks in advance!

https://codepen.io/tijmenjacobs/pen/wvdeaow

const checkForSections = () => {
  const optionsSections = {
    root: null,
    rootMargin: "-350px -150px",
    threshold: .9
  };

  const addHighlightClass = (entries) => {
    const [entry] = entries;
    const id = entry.target.getAttribute("id");

    if (entry.isIntersecting) {
      document
        .querySelector(`.navbar__link[href="#${id}"]`)
        .parentElement.classList.add("highlight");
    } else {
      document
        .querySelector(`.navbar__link[href="#${id}"]`)
        .parentElement.classList.remove("highlight");
    }
  };
  const observer = new IntersectionObserver(addHighlightClass, optionsSections);
  // Track sections
  Array.from(document.querySelectorAll("section[id]")).map((section) => {
    observer.observe(section);
  });
};

checkForSections();
* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

.navbar {
  position: fixed;
  width: 100%;
  padding: 2rem;
  background-color: cornflowerblue;
  display: flex;
  justify-content: center;
  align-items: center;
}

.navbar__list {
  list-style: none;
  display: flex;
}

.navbar__item {
  margin-left: 1rem;
}

.navbar__link,
.navbar__link:visited {
  color: inherit;
  text-decoration: none;
}

.navbar__link:hover,
.navbar__link:active,
.navbar__link:visited:hover,
.navbar__link:visited:active {
  color: red;
}

section {
  height: 100vh;
  text-align: center;
  padding: 5rem;
  display: flex;
  justify-content: center;
  align-items: center;
}

section h2 {
  color: #bada55;
  font-size: 5rem;
}

.highlight {
  color: red;
}
<nav class="navbar">
  <ul class="navbar__list">
    <li class="navbar__item"><a href="#home" class="navbar__link">Home</a></li>
    <li class="navbar__item"><a href="#about" class="navbar__link">About</a></li>
    <li class="navbar__item"><a href="#contact" class="navbar__link">Contacts</a></li>
  </ul>
</nav>

<body>
  <section id="home">
    <h2>Home</h2>
  </section>
  <section id="about">
    <h2>About</h2>
  </section>
  <section id="contact">
    <h2>Contact</h2>
  </section>
</body>

Upvotes: 2

Views: 57

Answers (1)

pilchard
pilchard

Reputation: 12919

Instead of only checking the first entry with const [entry] = entries; you can iterate through all entries and update accordingly.

const addHighlightClass = (entries) => {
  entries.forEach(entry => {
    const id = entry.target.getAttribute("id");

    if (entry.isIntersecting) {
      document
        .querySelector(`.navbar__link[href="#${id}"]`)
        .parentElement.classList.add("highlight");
    } else {
      document
        .querySelector(`.navbar__link[href="#${id}"]`)
        .parentElement.classList.remove("highlight");
    }
  })
};

Edited snippet:

const checkForSections = () => {
  const optionsSections = {
    root: null,
    rootMargin: "-350px -150px",
    threshold: .9
  };

  const addHighlightClass = (entries) => {
    entries.forEach(entry => {
      const id = entry.target.getAttribute("id");

      if (entry.isIntersecting) {
        document
          .querySelector(`.navbar__link[href="#${id}"]`)
          .parentElement.classList.add("highlight");
      } else {
        document
          .querySelector(`.navbar__link[href="#${id}"]`)
          .parentElement.classList.remove("highlight");
      }
    })
  };

  const observer = new IntersectionObserver(addHighlightClass, optionsSections);
  
  // Track sections
  Array.from(document.querySelectorAll("section[id]")).map((section) => {
    observer.observe(section);
  });
};

checkForSections();
* {  box-sizing: border-box;  padding: 0;  margin: 0;}.navbar {  position: fixed;  width: 100%;  padding: 2rem;  background-color: cornflowerblue;  display: flex;  justify-content: center;  align-items: center;}.navbar__list {  list-style: none;  display: flex;}.navbar__item {  margin-left: 1rem;}.navbar__link,.navbar__link:visited {  color: inherit;  text-decoration: none;}.navbar__link:hover,.navbar__link:active,.navbar__link:visited:hover,.navbar__link:visited:active {  color: red;}section {  height: 100vh;  text-align: center;  padding: 5rem;  display: flex;  justify-content: center;  align-items: center;}section h2 {  color: #bada55;  font-size: 5rem;}.highlight {  color: red;}
<nav class="navbar">  <ul class="navbar__list">    <li class="navbar__item"><a href="#home" class="navbar__link">Home</a></li>    <li class="navbar__item"><a href="#about" class="navbar__link">About</a></li>    <li class="navbar__item"><a href="#contact" class="navbar__link">Contacts</a></li>  </ul></nav><body>  <section id="home">    <h2>Home</h2>  </section>  <section id="about">    <h2>About</h2>  </section>  <section id="contact">    <h2>Contact</h2>  </section></body>

Upvotes: 1

Related Questions