javascripthtmlcssscrollspy

Scrollspy overflow-x:scroll menu


I'm doing something with Scrollspy. But I ran into a problem and couldn't find a solution. when I scroll, I want it to follow the nav-item on my navbar slider. Because I can't see what part he's in when there's a lot of sections. how can I solve this? I tried bootstrap's scrollspy component, but it didn't work there, I wonder if anyone has a better solution? Thanks in advance

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>VanillaJS ScrollSpy</title>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css"
    />
    <style>
      html,
      body {
        height: 100%;
      }
      .navbar-start {
        width: 300px;
        overflow-y: scroll;
        display: flex;
        margin-left: auto;
        margin-right: auto;
        border: 2px solid #fff;
      }
      .navbar-brand > .navbar-item {
        font-size: 20px;
        font-weight: bold;
      }
      .navbar-menu .navbar-item {
        font-size: 14px;
        transition: background-color 0.26s, color 0.26s;
      }
      .navbar-menu .navbar-item.active {
        background-color: #222;
        color: red;
      }
      .page {
        height: 100%;
        padding: 80px 0;
        width: 100%;
      }
      .page:nth-child(odd) {
        background-color: #ddd;
      }
      .page:nth-child(even) {
        background-color: #fff;
      }
    </style>
  </head>

  <body>
    <nav
      class="navbar is-dark is-fixed-top"
      role="navigation"
      aria-label="main navigation"
    >
      <div class="container">
        <div id="navbar" class="navbar-menu navbar-scroll">
          <div class="navbar-start">
            <a href="#section1" class="navbar-item active">Section-1</a>
            <a href="#section2" class="navbar-item">Section-2</a>
            <a href="#section3" class="navbar-item">Section-3</a>
            <a href="#section4" class="navbar-item">Section-4</a>
            <a href="#section5" class="navbar-item">Section-5</a>
            <a href="#section6" class="navbar-item">Section-6</a>
            <a href="#section7" class="navbar-item">Section-7</a>
            <a href="#section8" class="navbar-item">Section-8</a>
            <a href="#section9" class="navbar-item">Section-9</a>
            <a href="#section10" class="navbar-item">Section-10</a>
            <a href="#section11" class="navbar-item">Section-11</a>
            <a href="#section12" class="navbar-item">Section-12</a>
          </div>
        </div>
      </div>
    </nav>

    <section id="section1" class="page">
      <div class="container">
        <h2 class="title">Section 1</h2>
      </div>
    </section>

    <section id="section2" class="page">
      <div class="container">
        <h2 class="title">Section 2</h2>
      </div>
    </section>

    <section id="section3" class="page">
      <div class="container">
        <h2 class="title">Section 3</h2>
      </div>
    </section>

    <section id="section4" class="page">
      <div class="container">
        <h2 class="title">Section 4</h2>
      </div>
    </section>

    <section id="section5" class="page">
      <div class="container">
        <h2 class="title">Section 5</h2>
      </div>
    </section>

    <section id="section6" class="page">
      <div class="container">
        <h2 class="title">Section 6</h2>
      </div>
    </section>

    <section id="section7" class="page">
      <div class="container">
        <h2 class="title">Section 7</h2>
      </div>
    </section>

    <section id="section8" class="page">
      <div class="container">
        <h2 class="title">Section 8</h2>
      </div>
    </section>

    <section id="section9" class="page">
      <div class="container">
        <h2 class="title">Section 9</h2>
      </div>
    </section>

    <section id="section10" class="page">
      <div class="container">
        <h2 class="title">Section 10</h2>
      </div>
    </section>

    <section id="section11" class="page">
      <div class="container">
        <h2 class="title">Section 11</h2>
      </div>
    </section>

    <section id="section12" class="page">
      <div class="container">
        <h2 class="title">Section 12</h2>
      </div>
    </section>

    <script src="vanillajs-scrollspy.min.js"></script>
    <script>
      const navbar = document.querySelector("#navbar");
      const scrollspy = new VanillaScrollspy(navbar);
      scrollspy.init();
    </script>
  </body>
</html>


Solution

  • As VanillaScrollspy does not have any event attached to it, I have modified its core js file and called a function when this update the class of the nav items. I have created a function named "update_nav_menu_position" and this works like this

    update_nav_menu_position = function(){
        // using jquery here
        var $active_nav_item = $("#navbar").find('a.active'),
            $scroll_elem = $(".navbar-start"),
            left_pos, right_limit, active_elem_left_pos, active_elem_right_pos, scroll_pos, new_scroll_pos;
    
        if( ! $active_nav_item.length ) {
            return false;
        }
    
        left_pos = $scroll_elem.offset().left;
        right_limit = $scroll_elem.width() + left_pos;
        active_elem_left_pos = $active_nav_item.offset().left;
        active_elem_right_pos = $active_nav_item.width() + active_elem_left_pos;
        scroll_pos = $scroll_elem.scrollLeft();
    
        if( active_elem_left_pos > left_pos && active_elem_right_pos < (right_limit - 50) ) {
            return true;
        } else {
            new_scroll_pos = (left_pos + right_limit) / 2;
            new_scroll_pos = active_elem_left_pos - new_scroll_pos;
            new_scroll_pos = scroll_pos + new_scroll_pos;
            $scroll_elem.scrollLeft(new_scroll_pos);
        }
    
    }
    

    I have initialised the function variable at the top of the page.

    Here is a working sample for your file. https://codepen.io/ympervej/pen/XWMvKqg

    Check line 200 where I called the function.