On your example site each <a>
tag there has a <span>
element that serves as the underline. But I'm thinking maybe we can cut off the markup and use border-bottom
instead. Basically there are two events that plays here - scroll()
and click()
.
This is basic the markup:
<nav>
<a>Home</a>
<a>About</a>
<a>Portfolio</a>
<a>Contact</a>
</nav>
<div id="contents">
<section>Home</section>
<section>About</section>
<section>Portfolio</section>
<section>Contact</section>
</div>
CSS, just would like to emphasize border:
a {
border:0 solid #FFF;
border-bottom-width:0;
}
jQuery scroll()
event:
$(window).scroll(function () {
//get the window scrollTop on scroll
var st = $(window).scrollTop();
/* we use each() to iterate on every section and
check if the offset position is in relative condition to the
scrollTop value
*/
$('#contents section').each(function (index) {
var offsetTop = $(this).offset().top,
h = $(this).height();
//this condition satisfies that this section is currently on the viewport
if (st >= offsetTop && st < offsetTop + h) {
/*find the nav <a> that has the same index to this section
currently on the viewport and
show its border-bottom by setting its width.
*/
$('nav a').eq(index).css({
'border-bottom-width': '3px'
});
} else {
//hide the border-bottom
$('nav a').eq(index).css({
'border-bottom-width': '0'
});
}
});
}).trigger('scroll');
nav <a>
click()
event:
$('nav a').click(function () {
/* click has no index argument compared to each() function
so we have to get it with index() */
var index = $(this).index(),
$target = $('#contents section').eq(index); // find the target section
//animate scrolling to the target section
$('html, body').stop(true, true).animate({
scrollTop: $target.offset().top
}, 'slow');
});
Note that we are using index
to target the exact <section>/<a>
, this solution will work properly if <section>
is arranged accordingly to nav <a>
arrangement position.
See this sample jsfiddle.