1

I'm looking to make a left to right scrolling navigation menu that's items are highlighted as you scroll down the page. This navigation will look similarly to the following in page navigation on Chase.com (https://www.chase.com/digital/customer-service?jp_cmp=rb/tap/off/na/prt). Please note that I want this navigation to stay scrollable on all devices.

Below is what I have so far. I'm currently having the issue with getting the nav options to scroll into focus as they are highlighted.

window.onscroll = function() {
  myFunction()
};

var navbar = document.getElementById("inpagenav");
var sticky = inpagenav.offsetTop;

function myFunction() {
  if (window.pageYOffset >= sticky) {
    inpagenav.classList.add("sticky")
  } else {
    inpagenav.classList.remove("sticky");
  }
}
// cache the navigation links 
var $navigationLinks = $('#inpagenav > ul > li > a');
// cache (in reversed order) the sections
var $sections = $($(".pagenavsection").get().reverse());

// map each section id to their corresponding navigation link
var sectionIdTonavigationLink = {};
$sections.each(function() {
  var id = $(this).attr('id');
  sectionIdTonavigationLink[id] = $('#inpagenav > ul > li > a[href=\\#' + id + ']');
});

// throttle function, enforces a minimum time interval
function throttle(fn, interval) {
  var lastCall, timeoutId;
  return function() {
    var now = new Date().getTime();
    if (lastCall && now < (lastCall + interval)) {
      // if we are inside the interval we wait
      clearTimeout(timeoutId);
      timeoutId = setTimeout(function() {
        lastCall = now;
        fn.call();
      }, interval - (now - lastCall));
    } else {
      // otherwise, we directly call the function 
      lastCall = now;
      fn.call();
    }
  };
}

function highlightNavigation() {
  // get the current vertical position of the scroll bar
  var myPadding = $('#inpagenav').height();
  var scrollPosition = $(window).scrollTop();

  // iterate the sections
  $sections.each(function() {
    var currentSection = $(this);
    // get the position of the section
    var sectionTop = currentSection.offset().top;

    // if the user has scrolled over the top of the section  
    if (scrollPosition + myPadding >= sectionTop) {
      // get the section id
      var id = currentSection.attr('id');
      // get the corresponding navigation link
      var $navigationLink = sectionIdTonavigationLink[id];
      // if the link is not active
      if (!$navigationLink.hasClass('active')) {
        // remove .active class from all the links
        $navigationLinks.removeClass('active');
        // add .active class to the current link
        $navigationLink.addClass('active');
      }
      // we have found our section, so we return false to exit the each loop
      return false;
    }
  });
}


$(window).scroll(throttle(highlightNavigation, 100));

// if you don't want to throttle the function use this instead:
// $(window).scroll( highlightNavigation );
.mainimage {
  text-align: center;
  height: 300px;
  background: gray
}

nav {
  background: white;
}

.sticky {
  position: fixed;
  top: 0;
  width: 100%;
}

nav ul {
  list-style: none;
  padding: 0rem;
  overflow: auto;
  white-space: nowrap;
  margin: 0rem;
  overflow-x: scroll;
}

nav ul::-webkit-scrollbar-thumb {
  background: #000;
}

nav ul li {
  padding-top: 1rem;
  vertical-align: center;
  display: inline-block;
}

nav ul li a {
  text-decoration: none;
  color: dodgerblue;
  display: inline-block;
  margin: 0rem 2rem;
  padding-bottom: 1rem;
  border-bottom: 3px solid transparent;
}

nav ul li a:hover {
  color: #0054a4;
  border-bottom: 3px solid #0054a4;
}

nav ul li .active {
  color: #308ce3;
  font-weight: bold;
  border-bottom: 3px solid #308ce3;
}

#section1 {
  text-align: center;
  height: 500px;
  padding: 4rem 0rem;
  background: orange;
}

#section2 {
  text-align: center;
  height: 200px;
  padding: 4rem 0rem;
  background: green;
}

#section3 {
  text-align: center;
  height: 300px;
  padding: 4rem 0rem;
  background: blue;
}

#section4 {
  text-align: center;
  height: 500px;
  padding: 4rem 0rem;
  background: red;
}

#section5 {
  text-align: center;
  height: 500px;
  padding: 4rem 0rem;
  background: pink;
}

#section6 {
  text-align: center;
  height: 500px;
  padding: 7rem 0rem;
  background: purple;
}

#section7 {
  text-align: center;
  height: 500px;
  padding: 7rem 0rem;
  background: purple;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="menu.css">

<body>
  <div id="contentwrapper">
    <div class="mainimage">
      <h1>The whole world</h1>
    </div>

    <nav id="inpagenav">
      <ul>
        <li><a href="#section1" class="section1">Section 1</a></li>
        <li><a href="#section2" class="section2">Section 2</a></li>
        <li><a href="#section3" class="section3">Section 3</a></li>
        <li><a href="#section4" class="section4">Section 4</a></li>
        <li><a href="#section5" class="section5">Section 5</a></li>
        <li><a href="#section6" class="section6">Section 6</a></li>
      </ul>
    </nav>
    <section id="section1" class="pagenavsection">
      I'm section 1
    </section>
    <section id="section2" class="pagenavsection">
      I'm section 2
    </section>
    <section id="section3" class="pagenavsection">
      I'm section 3
    </section>
    <section id="section4" class="pagenavsection">
      I'm section 4
    </section>
    <section id="section5" class="pagenavsection">
      I'm section 5
    </section>
    <section id="section6" class="pagenavsection">
      I'm section 6
    </section>
    <section id="section7">lo</section>


  </div>
  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
  <script src="ScrollMenu.js"></script>


</body>

</html>

1 Answers1

0

You might just need to call $navigationLink.scrollIntoView() when you toggle the active class.

Per this answer, you may need to pass special options to scrollIntoView because the items are laid out horizontally.

$navigationLink.scrollIntoView({ inline: 'end' })
// end is my guess; allowable values are: start, center, end, or nearest (the default)
Tom
  • 8,509
  • 7
  • 49
  • 78