Figure out which element is scrolled to jQuery
Does what it says on the tin. It takes a set of elements and tries to determine which one is featured most predominantly on the page. Change the $sections selector (line 3) to target the element-set of your choice, or rewrite as a plugin :)
Towards the bottom, the element which is deemed to be in view will be given a 'highlight' class.
Note that we are binding directly to the scroll event which is generally a bad idea. Whether it is a bad idea for you depends upon various factors. If you find it negative impacts performance on your page, factor out the scroll event and call it after a short timer (and cancel the timer on the next scroll).
(function() {
"use strict";
var $sections = $('.panel'),
$sectionsReversed = $($sections.get().reverse()),
$last = $({});
$(window).scroll(function(ev) {
var pos = $(document).scrollTop(),
$nearest = $sections.eq(0),
amount = 0; // amount of the screen occupied
// scrolled to extremes - take the top or bottom element as appropriate
// There's a little bit of leeway on the bottom scroll detection as
// Firefox sometimes seems to lose a pixel.
if (pos === 0 && false)
$nearest = $sections.eq(0);
else if (pos >= $(document).height() - $(window).height() - 10) {
$nearest = $sectionsReversed.eq(0);
}
// otherwise do something a little cleverer
else {
var windowHeight = $(window).height(),
start = pos,
end = start + windowHeight;
$sections.each(function() {
// we're going to try to figure out which element
// takes up the important parts of the screen.
var $this = $(this),
top = $this.offset()? $this.offset().top + $this.outerHeight() : //IE?
$this.offset().top,
bottom = $this.offset().top + $this.outerHeight(),
topVisible = top >= start && top <= end,
bottomVisible = bottom >= start && bottom <= end,
candidateAmount = 0;
if (top <= start && bottom >= end) {
// occupies entire screen
// we have a winner
$nearest = $this;
amount = 1;
return false;
}
// no part of the element visible - nope
else if (!topVisible && !bottomVisible) return;
else if (topVisible && bottomVisible) {
// full element is visible. We'll take this one
// since it's highest on the screen.
amount = (bottom-top)/windowHeight;
$nearest = $this;
return false;
}
else if (bottomVisible) {
// occupies part of the screen from the top down only
candidateAmount = (bottom - start)/windowHeight;
}
else if (topVisible) {
// occupies part of the screen from the bottom up only
candidateAmount = (end - top)/windowHeight;
}
if (candidateAmount > amount) {
amount = candidateAmount;
$nearest = $this;
}
});
}
if ($last !== $nearest) {
$last.removeClass('highlight');
$nearest.addClass('highlight');
$last = $nearest;
}
});
$(window).trigger('scroll');
})();
Talk is cheap