Reputation: 5920
I have the following jQuery function which is supposed to detect when an element first scrolls into view on a page:
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
My mind is mush today... how can I use this function?
Assume I want to detect when $('.guardrail360')
comes into view.
Upvotes: 1
Views: 559
Reputation: 27770
There are several ways to do it. Just don't use a naive window.scroll
implementation if you are concerned with user experience and/or performance.
It's a very, very, bad idea to attach handlers to the window scroll event. Depending upon the browser the scroll event can fire a lot and putting code in the scroll callback will slow down any attempts to scroll the page (not a good idea). Any performance degradation in the scroll handler(s) as a result will only compound the performance of scrolling overall. Instead it's much better to use some form of a timer to check every X milliseconds OR to attach a scroll event and only run your code after a delay (or even after a given number of executions - and then a delay).
-John Resig, creator of jQuery, on ejohn.org
First, there is the naive approach using timers:
var $el = $('.guardrail360');
var timer = setInterval(function() {
if (isScrolledIntoView($el)) {
// do stuff
// to run this block only once, simply uncomment the next line:
//clearInterval(timer);
}
}, 150);
Then there is the trivial, yet crazy inefficient way using the scroll event (depending on the browser, the scroll event will fire hundreds of times per second, so you do NOT want to run a lot of code in here, particularly not code that triggers browser reflows/redraws).
Ever visited a site where scrolling down the page felt sluggish and jittery? That is often caused by a piece of code like this one right here:
var $el = $('.guardrail360');
$(window).on('scroll', function() {
if (isScrolledIntoView($el)) {
// do stuff
}
});
The nifty hybrid approach for high traffic sites, as proposed by John Resig in the aforementioned blog post:
var $el = $('.guardrail360'),
didScroll = false;
$(window).scroll(function() {
didScroll = true;
});
var timer = setInterval(function() {
if ( didScroll ) {
didScroll = false;
if (isScrolledIntoView($el)) {
// do stuff
// to run this block only once, simply uncomment the next line:
//clearInterval(timer);
}
}
}, 250);
Throttling (minimum N milliseconds between invocations) or debouncing (only one invocation per 'burst') patterns can also be used to efficiently limit the rate at which your inner code executes. Assuming you'd be using Ben Alman's jQuery throttle/debounce plugin, the code looks like this:
var $el = $('.guardrail360');
// Throttling
$(window).on('scroll', $.throttle( 250, function(){
if (isScrolledIntoView($el)) {
// do stuff
}
}));
// Debouncing
$(window).on('scroll', $.debounce( 250, function(){
if (isScrolledIntoView($el)) {
// do stuff
}
}));
(Note that debouncing acts slightly differently from the other implementations, but that can sometimes be what you want, depending on your user experience scenario)
Upvotes: 2
Reputation: 96790
if ( isScrolledIntoView('.guardrail360') ) {
}
As suggested by the other answers, you should use act upon $(window).scroll()
. In addition, in order to make the if statement run the first time the element is scrolled into view, I created this run_once
function for you:
$('window').on('scroll', function() {
if ( isScrolledIntoView('.guardrail360') ) run_once(function() {
// ...
});
});
function run_once( callback ) {
var done = false;
return function() {
if ( !done ) {
done = true;
return callback.apply( this, arguments );
}
};
}
Upvotes: 0
Reputation: 3873
Seems like you need to bind the scroll event and do the detection when that event fires.
$(window).scroll(function () {
isScrolledIntoView('.guardrail360');
});
Upvotes: 2