tags:

views:

312

answers:

3

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.

A: 

You can use $(window).scrollTop(); to know how far you've gone from the very top.

JS:

$(window).scroll(
    function() {

       var top = 0;
       top = $(window).scrollTop();

       if(top < 500){
         $("a[href='#top']").parent().addClass("current");
         $("a[href='#top']").parent().siblings().removeClass("current");
       }

       if((top >= 500) && (top < 1000)){
         $("a[href='#work']").parent().addClass("current");
         $("a[href='#work']").parent().siblings().removeClass("current");
       }    

       if((top >= 1000) && (top < 1500)){      
         $("a[href='#blog']").parent().addClass("current");
         $("a[href='#blog']").parent().siblings().removeClass("current");
        }   

CSS:

<style type="text/css">
body{
height: 2000px;
}
div#nav{
position: fixed;
top: 170px;
z-index: 10;
}
#nav ul li{
display: block;
margin: 0;
padding: 0;
background: #FFFFFF;
}
#nav ul li a{
backgroundColor: #FFFFFF;
color: #C55500;
}
#nav ul li.current a{
background: none repeat scroll 0 0 #303E3F;
color: #FFFFFF;
}
#nav ul li a{
-moz-border-radius: 5px 5px 5px 5px;
display: block;
line-height: 1;
padding: 10px;
text-align: right;
text-decoration: none;
width: 70px;
}

HTML:

<div id="nav">
  <ul>
    <li><a title="" href="#top">Home</a></li>
    <li><a title="" href="#work">Work</a></li>
    <li><a href="#blog" title="">Blog</a></li>

  </ul>
</div>
SteD
A: 

Nice, thanks that's helped me to understand the relationships between the window the links but I didn't want to use specific pixel heights but instead relate to the divs that hold the content for each link. The original site I showed uses the following:

function animateMenuLogo(logo, menu) {
    var scrollposition = $(window).scrollTop();
    var top = $("a[name='"+ menu +"']").offset().top;
    var sectionheight = $("a[name='"+ menu +"']").next().outerHeight();

    if (((top-100) < scrollposition) && ((top+sectionheight-200) > scrollposition)) {
        $(logo).fadeIn(500);
        $("a[href='#"+ menu +"']").css({ backgroundColor: "#303e3f", color: "#ffffff" });
        $("a[href='#"+ menu +"']").parent().addClass("current");
    } else {
        $(logo).fadeOut(500);
        $("a[href='#"+ menu +"']").css("background-color","transparent");
        $("a[href='#"+ menu +"']").css("color","#717c7d");$("a[href='#"+ menu +"']").parent().removeClass("current");
    }       
}

Now, this is only part of the code and it also controls the logo that comes in on the right, but the part that interests (and confuses) me is the variables scrollposition and sectionheight which must enable the menu to change class based on whether or not the section is in view.

Jonny Wood
A: 

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');
   }
  });
 });

});
fudgey
perfect! Thank you, and thanks for commenting the code, really helps with getting my head around jQuery
Jonny Wood
Just discovered a problem with this method. Although it works perfectly with standard html content within each .content div if you want to use tabs (hidden content) then the scrolling becomes jumpy and irratic.
Jonny Wood
If you are trying to scroll content inside of a tab pane, try using `$('.ui-tabs-panel:visible').scrollTop`, `$('.ui-tabs-panel:visible').height()` and `$('.content:visible').height()`... I think that should cover it.
fudgey