Brian
Brian

Reputation: 528

Highlight my navbar menu items whenever I scroll through that section? Only using Javascript

I currently have my nav menu items highlighted whenever I click them, but I want the entire section in the HTML to have a highlighted background, so when the user is scrolling through the website, it will automatically highlight the nav menu item according to the whichever section they are scrolling through

Here is an example on codepen that I'm trying to achieve with my code https://codepen.io/joxmar/pen/NqqMEg

Here is my current landing page in Jsfiddle https://jsfiddle.net/hzg02k3n/

As you can see from my jsfiddle, the links get highlights when I click, but I need it to become active whenever I scroll over the section.

Below my current HTML code

<header class="page__header">
      <nav class="navbar__menu">
        <!-- Navigation starts as empty UL that will be populated with JS -->
        <ul id="navbar__list"></ul>
      </nav>
    </header>
    <main>
      <header class="main__hero">
        <h1>Landing Page</h1>
      </header>
<section id="section1" data-nav="Section 1" class="active">
        <div class="landing__container">
          <h2>Section 1</h2>
          <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi
            fermentum metus faucibus lectus pharetra dapibus. Suspendisse
            potenti. Aenean aliquam elementum mi, ac euismod augue. Donec eget
            lacinia ex. Phasellus imperdiet porta orci eget mollis. Sed
            convallis sollicit
          </p>

          <p>
            Aliquam a convallis justo. Vivamus venenatis, erat eget pulvinar
            gravida, ipsum l
          </p>
        </div>
      </section>
      <section id="section2" data-nav="Section 2">
        <div class="landing__container">
          <h2>Section 2</h2>
          <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi
            fermentum metus faucibus lectus pharetra dapibus. Suspendisse
            potenti. Aenean aliquam elementum mi, ac euismod augue. Donec eget
            lacinia ex. Phasellus imperdiet porta orci eget mollis. Sed
            convallis s
          </p>

          <p>
            Aliquam a convallis justo. Vivamus venenatis, erat eget pulvinar
            gravida, ipsum l
          </p>
        </div>
      </section>

I have up to 4 sections, but this just shows the first two.

Here is my Javascript that I used to create the navbar

const navMenu = document.querySelectorAll("section");
const navList = document.getElementById("navbar__list");
const items = ["Section 1", "Section 2", "Section 3", "Section 4"];

//Build the nav
items.forEach((item, i) => {
  const el = document.createElement("a");
  el.innerText = item;
  el.classList.add("menu-items");
  el.setAttribute("id", `menu-${i + 1}`);
  el.href = `#section${i + 1}`;
  navList.appendChild(el);

  const li = document.createElement("li");
  li.classList.add("menu-list");
  li.appendChild(el);
  li.setAttribute("id", `${i + 1}`);
  // Append the list item to the list
  navList.appendChild(li);
});

//Make Nav Active when Clicked and scrolls down to section
document.addEventListener("click", function (event) {
  let active = document.querySelector(".menu-list.active");
  if (active) active.classList.remove("active");
  if (event.target.classList.contains("menu-list")) {
    event.target.classList.add("active");
    window.location.href = "#section" + event.target.id;
  }
});

Upvotes: 1

Views: 10636

Answers (1)

Evan Bechtol
Evan Bechtol

Reputation: 2865

Just utilize the mouseover and mouseout events!

Here is a small example & here is a JS Fiddle as well:

const navMenu = document.querySelectorAll("section");
const navList = document.getElementById("navbar__list");
const items = ["Section 1", "Section 2", "Section 3", "Section 4"];
let lastId;
let last_known_scroll_position = 0;
let ticking = false;

//Build the nav
items.forEach((item, i) => {
  const li = document.createElement("li");
  const el = document.createElement("a");
  el.innerText = item;
  el.classList.add("menu-items");
  el.setAttribute("id", `menu-${i + 1}`);
  el.href = `#section${i + 1}`;

  el.addEventListener("click", function(e) {
    const href = e.target.getAttribute("href"),
      offsetTop = href === "#" ? 0 : e.target.offsetTop - topMenuHeight + 1;
    const scrollOptions = {
      scrollIntoView: true,
      behavior: "smooth"
    };
    e.target.scrollIntoView(scrollOptions);
    e.preventDefault();
  });

  navList.appendChild(li);
  li.appendChild(el);
});

const topMenu = document.getElementById("navbar__list");
const topMenuHeight = topMenu.offsetHeight + 1;
const menuItems = document.querySelectorAll(".menu-items");
const scrollItems = document.querySelectorAll(".sec");

//Make Nav Active when Clicked and scrolls down to section
document.addEventListener("click", function(event) {
  let active = document.querySelector(".active");
  if (active) {
    active.classList.remove("active");
  }
  if (event.target.classList.contains("menu-items")) {
    event.target.classList.add("active");
  }
});

// Bind to scroll
window.addEventListener("scroll", function() {
  // Get container scroll position
  const container = document.querySelector(".container");
  let fromTop = window.pageYOffset + topMenuHeight + 40;

  // Get id of current scroll item
  let cur = [];

  [...scrollItems].map(function(item) {
    if (item.offsetTop < fromTop) {
      cur.push(item);
    }
  });

  // Get the id of the current element
  cur = cur[cur.length - 1];
  let id = cur ? cur.id : "";

  if (lastId !== id) {
    lastId = id;

    menuItems.forEach(function(elem, index) {
      elem.classList.remove("active");
      const filteredItems = [...menuItems].filter(elem => elem.getAttribute("href") === `#${id}`);
      filteredItems[0].classList.add("active");
    });
  }
});
body {
  font-family: "Arial", sans-serif;
}

#navbar__list {
  height: 40px;
  background-color: #55443D;
  display: block;
  align-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  z-index: 1;
  margin: 0 auto;
}

#navbar__list ul {
  padding: 0;
  list-style: none;
  position: relative;
  display: table;
  margin: 0 auto;
}

#navbar__list li {
  display: table-cell;
}

#navbar__list li a {
  padding: 10px 20px;
  display: block;
  color: white;
  text-decoration: none;
  transition: all 0.3s ease-in-out;
}

#navbar__list li a:hover {
  color: #dc5c26;
}

#navbar__list li a .active {
  color: #F38A8A;
  border-bottom: 3px solid #F38A8A;
}

.active {
  color: #F38A8A;
  border-bottom: 3px solid #F38A8A;
}

.sec {
  height: 50vh;
  display: block;
}

.sec h2 {
  position: relative;
  top: 50%;
  left: 50%;
}

#section1 {
  background-color: green;
}

#section2 {
  background-color: yellow;
}

#section3 {
  background-color: blue;
}

#section4 {
  background-color: grey;
}
<ul id="navbar__list"></ul>

<section class="container">
  <div id="section1" class="sec">
    <h2>Section 1</h2>
  </div>
  <div id="section2" class="sec">
    <h2>Section 2</h2>
  </div>
  <div id="section3" class="sec">
    <h2>Section 3</h2>
  </div>
  <div id="section4" class="sec">
    <h2>Section 4</h2>
  </div>
</section>

Edit: This is the working fiddle using your code

Upvotes: 5

Related Questions