Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery changing css on navigation when div # scrolls into view

Tags:

jquery

css

height

I'm looking to recreate the effect used on this site: http://www.brizk.com/

The site uses one large page that scrolls down. As you scroll down and pass different sections the menu navigation on the left changes css class to "current" as the corresponding div comes into view.

I presume this can be done with jQuery using $(window).height();

I'm fairly new to jQuery and what I want to write is something like this (in laymans terms):

  • Get height of browser window – if div#content1 is 100px from top and/or 200px from bottom change menu a#link1 to '.current' – else remove .current from all menu a links

... and repeat for 4 different content divs.

Can anyone point me in the right direction..? Thanks.

like image 819
Mr Jonny Wood Avatar asked May 24 '10 12:05

Mr Jonny Wood


1 Answers

I didn't look at the code example (it's more fun to challenge myself :P) but this is how I would do it - demo here.

I saved the position of each element block to minimize the number of DOM calls, then just searched through the array. To help you understand some of the variables.

$(window).height() // returns the viewport height
$(document).height() // returns the height of the entire document
$(window).scrollTop() // returns the Y position of the document that is at the top of the viewport

Script:

var topRange      = 200,  // measure from the top of the viewport to X pixels down
    edgeMargin    = 20,   // margin above the top or margin from the end of the page
    animationTime = 1200, // time in milliseconds
    contentTop = [];

$(document).ready(function(){

 // Stop animated scroll if the user does something
 $('html,body').bind('scroll mousedown DOMMouseScroll mousewheel keyup', function(e){
  if ( e.which > 0 || e.type == 'mousedown' || e.type == 'mousewheel' ){
   $('html,body').stop();
  }
 });

 // Set up content an array of locations
 $('#sidemenu').find('a').each(function(){
  contentTop.push( $( $(this).attr('href') ).offset().top );
 });

 // Animate menu scroll to content
  $('#sidemenu').find('a').click(function(){
   var sel = this,
       newTop = Math.min( contentTop[ $('#sidemenu a').index( $(this) ) ], $(document).height() - $(window).height() ); // get content top or top position if at the document bottom
   $('html,body').stop().animate({ 'scrollTop' : newTop }, animationTime, function(){
    window.location.hash = $(sel).attr('href');
   });
   return false;
 });

 // adjust side menu
 $(window).scroll(function(){
  var winTop = $(window).scrollTop(),
      bodyHt = $(document).height(),
      vpHt = $(window).height() + edgeMargin;  // viewport height + margin
  $.each( contentTop, function(i,loc){
   if ( ( loc > winTop - edgeMargin && ( loc < winTop + topRange || ( winTop + vpHt ) >= bodyHt ) ) ){
    $('#sidemenu li')
     .removeClass('selected')
     .eq(i).addClass('selected');
   }
  });
 });

});
like image 131
Mottie Avatar answered Sep 22 '22 07:09

Mottie