1

I have done a custom menu with a parallax style. The menu is fixed on top and I want to change the active class for the menu when page scrolls. I have done it by click function so by clicking the menu the active class change to that particular menu. I created this menu with id not 'href="#home"'. Most of the code I find is done by href="#" and nav. I don't want the menu to be one with nav navbar. So can it be done by id?

My codes are below

  $("#home-btn").on('click',function() {
  $('html, body').animate({
   scrollTop : $("#home").offset().top - 10
  }, 1000);
  $('.main-menu ul li').removeClass('active');
  $('#home-btn').parent().addClass('active');
 });
 
 $("#service-btn").on('click',function() {
  $('html, body').animate({
   scrollTop : $("#service").offset().top - 45
  }, 1000);
  $('.main-menu ul li').removeClass('active');
  $('#service-btn').parent().addClass('active');
 });
 
 $("#about-btn").on('click',function() {
  $('html, body').animate({
   scrollTop : $("#about").offset().top - 120
  }, 1000);
  $('.main-menu ul li').removeClass('active');
  $('#about-btn').parent().addClass('active');
 });
 
 $("#contact-btn").on('click',function() {
  $('html, body').animate({
   scrollTop : $("#contact").offset().top - 120
  }, 2000);
  $('.main-menu ul li').removeClass('active');
  $('#contact-btn').parent().addClass('active');
 });
.top-adj {
  margin-top: 130px;
}

.main-menu {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background: #f1f1f1;
}

.main-menu ul {
 display: flex;
 align-items: center;
 justify-content: space-between;
}

.main-menu ul li {
 display: block;
 font-weight: 600;
 margin-left: 25px;
}

.main-menu ul li:first-child {
 margin-left: 0px;
}

.main-menu ul li a {
 color: #000;
 display: block;
 cursor: pointer;
 padding: 25px 10px;
 position: relative;
 border-bottom: 4px solid;
 border-color: transparent;
}

.main-menu ul li a:hover {
 text-decoration: none;
}

.main-menu ul li.active a {
 padding: 25px 10px;
 border-bottom: 4px solid #104377;
}

.section {
  width: 100%;
  height: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 <div class="main-menu">
   <ul>
       <li class="active"><a id="home-btn">Home</a></li>
         <li><a id="service-btn">Services</a></li>
         <li><a id="about-btn">About</a></li>
         <li><a id="contact-btn">Contact</a></li>
    </ul>
 </div>

<div class="top-adj"></div>
<div class="section" id="home">Home</div>
<div class="section" id="service">Service</div>
<div class="section" id="about">About</div>
<div class="section" id="contact">Contact</div>
User113
  • 153
  • 1
  • 2
  • 14

2 Answers2

0

Here we have selected all the elements using the querySelectorAll method of Vanilla JavaScript.

You can get more idea about Array.prototype.forEach.call() function here.

We have used window.onscroll event to perform our scroll spy in which we have matched the top offset of each section with the scroll position of windows and added class based on it.

(function () {
  var section = document.querySelectorAll(".section");
  var sections = {};
  var i = 0;

  Array.prototype.forEach.call(section, function (e) {
      sections[e.id] = e.offsetTop;
  });

  window.onscroll = function () {
      var scrollPosition = document.documentElement.scrollTop ||
          document.body.scrollTop;

      for (i in sections) {
          if (sections[i] <= scrollPosition) {
              document.querySelector('.active').setAttribute('class', ' ');
              document.querySelector('a[id*=' + i +
                  ']').parentElement.setAttribute('class', 'active');
          }
      }
  };

  // Your code
  $("#home-btn").on('click', function () {
      $('html, body').animate({
          scrollTop: $("#home").offset().top
      }, 1000);
  });

  $("#service-btn").on('click', function () {
      $('html, body').animate({
          scrollTop: $("#service").offset().top
      }, 1000);
  });

  $("#about-btn").on('click', function () {
      $('html, body').animate({
          scrollTop: $("#about").offset().top
      }, 1000);
  });

  $("#contact-btn").on('click', function () {
      $('html, body').animate({
          scrollTop: $("#contact").offset().top
      }, 2000);
  });
})();
.top-adj {
  margin-top: 130px;
}

.main-menu {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background: #f1f1f1;
}

.main-menu ul {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.main-menu ul li {
  display: block;
  font-weight: 600;
  margin-left: 25px;
}

.main-menu ul li:first-child {
  margin-left: 0px;
}

.main-menu ul li a {
  color: #000;
  display: block;
  cursor: pointer;
  padding: 25px 10px;
  position: relative;
  border-bottom: 4px solid;
  border-color: transparent;
  text-decoration: none;
}

.main-menu ul li a:hover {
  text-decoration: none;
}

.main-menu ul li.active a {
  padding: 25px 10px;
  border-bottom: 4px solid #104377;
}

.section {
  width: 100%;
  height: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="main-menu">
   <ul>
     <li class="active"><a id="home-btn">Home</a></li>
     <li><a id="service-btn">Services</a></li>
     <li><a id="about-btn">About</a></li>
     <li><a id="contact-btn">Contact</a></li>
    </ul>
 </div>

<div class="top-adj"></div>
<div class="section" id="home">Home</div>
<div class="section" id="service">Service</div>
<div class="section" id="about">About</div>
<div class="section" id="contact">Contact</div>

I hope this helps.

Viral
  • 935
  • 1
  • 9
  • 22
  • Read question ` created this menu with id not 'href="#home"'. Most of the code I find is done by href="#" and nav. I don't want the menu to be one with nav navbar. So can it be done by id?` – Akhil Aravind Feb 07 '20 at 06:36
  • there is a bug. clicking on menu active class in not active for that class. Please click contact button the active class is showing in about – User113 Feb 07 '20 at 06:43
  • Hi, @AkhilAravind Thank you for highlighting. I have updated my code. – Viral Feb 07 '20 at 07:01
  • @User113 I have updated my code based on your requirements. Please let me know if you have any concerns. – Viral Feb 07 '20 at 07:01
  • 1
    @Viral still you are not using `ID`, you are using `data-href` – Akhil Aravind Feb 07 '20 at 07:14
  • when i put this code on my webpage it's not working. Also can you pls do it in id. – User113 Feb 07 '20 at 07:26
  • @User113 I have updated my code and also I have checked this demo on my local system as well. Please let me know if you have any concerns! – Viral Feb 07 '20 at 11:18
  • @Viral It works but active class is not showing correctly. When click on about link active class shows on service. Please fix – User113 Feb 12 '20 at 05:41
  • @User113 It seems to be working correctly for me. Can you please regenerate this situation on codepen or jsfiddle? – Viral Feb 12 '20 at 06:19
0

This is the edited code of the upper comment.

(function () {
  var section = document.querySelectorAll(".section");
  var sections = {};
  var i = 0;

  Array.prototype.forEach.call(section, function (e) {
      sections[e.id] = e.offsetTop;
  });

  window.onscroll = function () {
      var scrollPosition = document.documentElement.scrollTop ||
          document.body.scrollTop;

      for (i in sections) {
          if (sections[i] <= scrollPosition) {
              $('.nav-item').parent().removeClass('active');
              document.querySelector('a[id*=' + i +
                  ']').parentElement.setAttribute('class', 'active');
          }
      }
  };

  // Your code
  $("#home-btn").on('click', function () {
      $('html, body').animate({
          scrollTop: $("#home").offset().top
      }, 1000);
  });

  $("#service-btn").on('click', function () {
      $('html, body').animate({
          scrollTop: $("#service").offset().top
      }, 1000);
  });

  $("#about-btn").on('click', function () {
      $('html, body').animate({
          scrollTop: $("#about").offset().top
      }, 1000);
  });

  $("#contact-btn").on('click', function () {
      $('html, body').animate({
          scrollTop: $("#contact").offset().top
      }, 2000);
  });
})();
.top-adj {
  margin-top: 40px;
}

.main-menu {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background: #f1f1f1;
}

.main-menu ul {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.main-menu ul li {
  display: block;
  font-weight: 600;
  margin-left: 25px;
}

.main-menu ul li:first-child {
  margin-left: 0px;
}

.main-menu ul li a {
  color: #000;
  display: block;
  cursor: pointer;
  padding: 4px 10px;
  position: relative;
  border-bottom: 4px solid;
  border-color: transparent;
  text-decoration: none;
}

.main-menu ul li a:hover {
  text-decoration: none;
}

.main-menu ul li.active a {
  padding: 4px 10px;
  border-bottom: 4px solid #104377;
}

.section {
  width: 100%;
  height: 100vh;
  padding-top:40px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="main-menu">
   <ul>
     <li><a class="nav-item" id="home-btn">Home</a></li>
     <li><a class="nav-item" id="service-btn">Services</a></li>
     <li><a class="nav-item" id="about-btn">About</a></li>
     <li><a class="nav-item" id="contact-btn">Contact</a></li>
    </ul>
 </div>

<div class="top-adj"></div>
<div class="section" id="home">Home</div>
<div class="section" id="service">Service</div>
<div class="section" id="about">About</div>
<div class="section" id="contact">Contact</div>