Detect when an element has scrolled into view
A question came up on one of our engineering lists the other day and I think it’s innocent enough to go ahead and share a simple solution I had came up with that solves this particular issue. Needless to say, I believe I’m not breaking the birch of “don’t be evil.” Furthermore, this gives me an excuse to write about something since I haven’t done so in a few months (*cough).
Anyway, the idea is basic. You have an element in the DOM sitting somewhere below the fold (see above the fold), and you’d like to know when it has breached through the bottom threshold of your screen as a user is scrolling down a page. An example of an application that uses this kind of logic would be, for instance, Google reader, where stories are loaded dynamically as the user scrolls more headlines into view. Since there could potentially be hundreds or even thousands of RSS entries from any given feed, we wouldn’t want to load all of them at once.
Le Code
I went ahead and prototyped this out quickly using Y.U.I. to save time on simply proving a concept. The code that come of it essentially looks like this:
JavaScript: scroll element into view
var Event = YAHOO.util.Event;
var Dom = YAHOO.util.Dom;
Event.on(window, 'load', function() {
var y = Dom.getY('ft');
Event.on(window, 'scroll', function() {
var top = (document.documentElement.scrollTop ?
document.documentElement.scrollTop :
document.body.scrollTop);
var vpH = Dom.getViewportHeight();
var coverage = parseInt(vpH + top);
if ( coverage >= y ) {
console.log('in view!!!');
}
});
});
What this logic is essentially telling us is that we need three key ingredients to solve for this.
- The Y coordinate of the target element
- The viewport height of the users window
- The amount a user has scrolled from the top
If we add the viewport and the scrolling area, we can calculate our coverage; and then compare that to our Y coordinate. If the coverage is greater than or equal to the Y coordinate, we have passed the threshold. Go ahead and have a look see of our example so far.
Modifications
Since we’ve proven the concept, we can now write a simple interface that allows us to pass any arbitrary element, and then turn it into a custom event. With that in mind, a la Sellsian approach (implement first, API later), we could do something like this:
element viewer implementation
YAHOO.example.ElementViewer('my-element', function(Y) {
console.log('my-element is in view at:' + Y);
});
Simply pass in an element (id or HTMLElement), then add a callback method which will return the Y coordinate of how far you’ve scrolled to get there. The interface would now simply look like this using YUI’s custom event interface:
JavaScript: Element Viewer API
YAHOO.example.ElementViewer = function(el, callback) {
var y = Dom.getY(el);
var o = new YAHOO.util.CustomEvent('element finder',
null,
true,
YAHOO.util.CustomEvent.FLAT
);
o.subscribe(callback);
function f() {
var top = (document.documentElement.scrollTop ?
document.documentElement.scrollTop :
document.body.scrollTop);
var vpH = Dom.getViewportHeight();
var view = parseInt(vpH + top);
if ( view >= y ) {
o.fire(view);
}
}
Event.on(window, 'scroll', f);
};
And there you have it. This allows us to do the same thing, except now with a fancy interface :). See the demonstration. Cheers.




July 26th, 2007 at 12:21 pm
Hey Dustin,
Sweet write-up. Short, simple, and to the point. Love it!
July 26th, 2007 at 1:00 pm
Thanks for the write up Dustin, and good to see you posting. This reminds me of something I wrote for CWM in my earlier JS days: http://www.christian-web-masters.com/articles/web_logging-scrolling-javascript.html
–Jim
July 26th, 2007 at 1:17 pm
Hi Dustin,
I must be doing something stupid ’cause I’m getting an error in fb’s console:
‘console is not defined’ (I just did an update to get the latest version 1.05)
But other than that, pretty cool! :)
Marc
July 26th, 2007 at 1:31 pm
@Frank: Thanks dude. It took me quite a while to develop this style of writing. Over explaining is often the death of my best writings.
@Jim: The page you linked is not available to unauthorized viewers. Nonetheless, I do remember that article being posted although I had never read it.
@Marc: It works for me. I think there is a bug in your Firebug installation. There is no reason that ‘console’ should be undefined. console.log is the most commonly used method in Firebug. I find it quite ironic that Firebug itself is reporting that back to you. However, I have had that happen to me before. I would simply try uninstalling then reinstalling Firebug a few times or find an older version.
July 26th, 2007 at 1:54 pm
Said by Dustin, “Over explaining is often the death of my best writings.”
Often a problem of mine as well.
Said by Dustin, “The page you linked is not available to unauthorized viewers. Nonetheless, I do remember that article being posted although I had never read it.”
Interesting…I didn’t realize that was protected content…and I am hurt you didn’t read it. ;)
Said by Dustin, “There is no reason that ‘console’ should be undefined.”
Agreed–it is working for me…
July 26th, 2007 at 4:22 pm
I’m getting “Console is not defined” error as well in FF2 on WinXP.
July 26th, 2007 at 5:46 pm
So clearly, this isn’t working for people named Marc…. I don’t know what to make of it. You can try downloading the code and swapping it out for an alert and watch what happens.
July 27th, 2007 at 7:53 am
Dustin, I think you should’ve added Firebug Lite to your test, because there are plenty of Firefox people who don’t read descriptions (which is why they report a “bug” to you although they don’t have Firebug installed) and don’t use Firefox at all.
I know, Firebug is awesome and for example, at my work in developing stage everyone is using console.error|log to debug things. But we shouldn’t rely on this extension, without detecting it first, don’t you think? :>
July 30th, 2007 at 4:10 am
:lol:
July 31st, 2007 at 4:52 am
Nice stuff - will certainly remember this.
Just for the record - I got errors i Firebug as well using XP and latest of both Firebug and Firefox. Although it usually works I have read somewhere that there may be some bugs regarding Firebug and the latest FF or something and it’s quite a weird bug because now when I tested around a bit it worked randomly among different sites and when I returned to your example it suddenly works.
Well, well - your examples are wonderfully even if Firebug may be flawed ;)
July 31st, 2007 at 5:57 am
I saw a cool demo yesterday of a page the monitored for you to scroll to the bottom of what would normally be a paginated list of results from a search. When the bottom was hit, an AJAX request was triggered for more results to be appended to the document.
August 2nd, 2007 at 12:33 am
I get errors from Firebug about console not being defined too
console is not defined
http://www.dustindiaz.com/basement/element-in-view2.html
Line 68
I’m not called marc or Marc
August 4th, 2007 at 2:01 pm
Dustin: Does not happen with the safari browser …
August 6th, 2007 at 7:50 am
Nice work … and talk about the simplicity of it !
August 7th, 2007 at 9:39 pm
Excellent .. (works for me) .. going to give one of my clients a cheap thrill with this .. they have this humungous users manual that we’ve been thunking of various ways to break down in reader-friendly chunks .. you da man ..
August 16th, 2007 at 11:25 am
This also pops up errors for people called Mark. I think it’s something as simple as Firefox does not have “console”… Oh wait, someone allready beat me to that one.
August 16th, 2007 at 5:24 pm
Nice! I like this. The one issue with it is that if the element is in view and you refresh the page the event is not fired until you scroll.
September 27th, 2007 at 1:03 pm
[...] I just read a good article by Dustin Diaz (formerly of YAHOO) about detecting where elements are in regards to scrolling and the viewport. It is simple and very powerful, so I thought I would share it with you. Also, I am overworked right now and have not had time to write any material of my own :(. element-scroll-into-view posted by admin at 3:49 pm [...]
November 27th, 2007 at 3:20 pm
Used this in a new project.. works nicely!
December 11th, 2007 at 11:28 am
[...] Detect when an element has scrolled into view [...]