i am dustin diaz

a JavaScriptr...

boosh.

don't worry about it.

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.

this is who i am

Hi, my name is Dustin Diaz and I'm an Engineer @ObviousCorp. Previously @Twitter, @Google, and @Yahoo, author of Strobist® Info co-author of JavaScript Design Patterns, co-creator of the Ender JavaScript Framework, a Photographer, and an amateur Mixologist. This is my website. Welcome!

On this site I write about JavaScript. You can also follow along with my open-source work on Github.

This site is optimized and works best in Microsoft Internet Explorer 6.