Change active menu item depending on scroll

Asked

Viewed 2,761 times

5

Does anyone know how to do the effect that activates/disables menu items depending on the scroll? Like for example on the site PHP the Right Way, menu items turn on/off as you scroll the page.

I tried to analyze the source code of the page and did not find and as I do not know the name of the technique(?) I could not find anything on the internet.

3 answers

6


I don’t think this feature has any special name. I made an example where you can get an idea, it was with jquery and not with native javascript. If you don’t help him this way say I withdraw the answer:

EXAMPLE

// animação scroll quando se clica no menu
$('span').on('click', function() {
  $("html, body").animate({
    scrollTop: $('#' +$(this).data('section')).offset().top // ir para a secção cujo o id é o valor do atributo `data-section` do item do menu onde clicamos
  }, 500);
});

// guardamos todas as distancias de cada secção até ao todo da página e respetivo id
var alturas = {};
$('.section').each(function () {
  alturas[$(this).prop('id')] = $(this).offset().top; // ex: alturas['section_2'] = 600
});

// quando fazemos scoll vamos percorrer o nosso obj alturas e comparar a altura de cada secção com o que já andamos em scroll
$(window).on('scroll', function() {
  for(var seccao in alturas) {
    if($(window).scrollTop() >= alturas[seccao]) {
      $('span').removeClass('active'); // removemos a classe ative
      $('span[data-section="' +seccao+ '"]').addClass('active'); // adicionamos a class active ao item do menu cuja data-section é igual ao id da secção que está a uma maior ou igual distancia do topo do que aquela que percorremos com o scroll
    }
  }
});
body {
 margin:0;
}
nav {
  position:fixed;
  top:0;
  background-color: #ffffff;
  left:0;
  height:100%;
}
span {
  display:block;
  border:1px solid;
  cursor: pointer;
}
.active {
  background-color: red;
}
.section {
  height:600px;
  width:400px;
  border:1px solid;
  text-align:center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<nav>
   <span class="active" data-section="section_1">
      Secção 1
   </span>
   <span data-section="section_2">
      Secção 2
   </span>
   <span data-section="section_3">
      Secção 3
   </span>
   <span data-section="section_4">
      Secção 4
   </span>
</nav>

<div id="section_1" class="section">
   Secção 1
</div>
<div id="section_2" class="section">
   Secção 2
</div>
<div id="section_3" class="section">
   Secção 3
</div>
<div id="section_4" class="section">
   Secção 4
</div>

  • 1

    Your "joke" answers the question. Just bring to the answer, not to depend on the link... Will one day the internet explode right? kkk

  • It was just to n get very extensive. I will post the answer

  • I added your code to the snippet, I hope it’s OK. p

2

The answer from @Miguel already has an example of how to do, so I will just show the code of the site that was referred to in the question.

How about we "steal" their source?

They use jQuery and anchors to make such functionality, as can be seen in the code below:

(function ($) {
    //Add current view's highlighting to the navigation

    /** helper for highlighting */
    function highlightNav(navLinks,id)
    {
        navLinks.filter('[href="/#'+id+'"]').addClass("active");
    }

    $(window).scroll(function() {
        //console.log("They see me scrollin, they hatin");

        //clear highlighting
        var navLinks = $('.site-navigation a');
        navLinks.removeClass("active");

        //calc current viewport
        var viewTop = $(window).scrollTop();
        var viewBottom = viewTop + $(window).height();

        //for all h1 and h2 elements, check if they are visible
        //performance tweak: stop each() after the first element is found to be behind view
        var previous = "";
        var foundOne = false;
        var fallback = "";
        $('h1, h2').each(function(i,e) {
            //get element position;
            var eTop = $(e).offset().top;
            var eBottom = eTop + $(e).height();
            var id=e.id;
            id = id.replace("_title", "");

            if (eTop >= viewTop) {
                //if we are passed the view and no heading was highlighted yet, store previous one as fallback
                if (! foundOne) {
                    fallback=previous;
                }
                if (eBottom <= viewBottom) {
                    highlightNav(navLinks, id);
                    foundOne = true;
                } else {
                    return false; //break the each(), the rest is below
                }
            }
            previous=id;
        });
        //no h1/h2 is in the viewport, so highlight the last one above
        if (! foundOne) {
            highlightNav(navLinks, fallback);
        }
    });
})(jQuery);

That code looks for the anchor that’s on scroll and adds the class active in the menu item.

If you want to study further, this code can be found on straight past.

Note that I did not find the origin of the code to post the copyright, so I posted what was found on the site cited in the question and Google searches.

0

Apparently, this effect is called Scrollspy. I found it on the page of Materialize CSS

Scrollspy is a jQuery plugin that monitors certain elements and which element is centered on user screen. Our main demonstration of this is our table of contents on all pages of documentation on the right. Clicking on these links will also scroll to page for the element.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.