HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Fading in while scrolling - is this an elegant solution?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thiswhilescrollingfadingelegantsolution

Problem

I have posted such question at StackOverflow but the single answer I got there was to ask here.

My task is to get elements fading in while the user is scrolling. Here is my link - http://layot.prestatrend.com/ I have made it with the help of such jQuery code I've gathered from two sources:


 $(document).ready( function() {

 tiles = $('.ajax_block_product').fadeTo(0,0);

 $(window).scroll(function(d,h) {
    tiles.each(function(i) {
        a = $(this).offset().top + $(this).height();
        b = $(window).scrollTop() + $(window).height();
        if (a 


Is this an elegant solution or is there a way to make the code shorter and more elegant?

Solution

The onScroll event is generally very performance hungry, since it is called quite often, while scrolling. Looping through all "ajax_block_product" elements on every singel call, even if most of them might be outside of the viewport, makes it even worse. But you can use some specialities of JS to optimize it. As a short intro: In JS you can set an array element at a defined index, leaving the ones in between undefined while having the length of the array set to the highest index defined.

a[100] = 'one';
a[1000] = 'two';
for (var i = 0; i < a.length; i++) {
    console.log('iterate'); // called 1000 times
}
for (var elm in a) {
    console.log('iterate'); // called two times
}


Now if you loop through the array with a typical for(var i = 0; i < a.length; i++) you will have 1000 iterations BUT since an array is also an object in JS a for(elm in a) would only iterate 2 times. We can now use this to store all Y-positions of "ajax_block_product" elements as indexes of an array, than determine the dimension of the current viewport and cut out only those element who are inside that range.

$(document).ready(function () {
    var tiles = $('.ajax_block_product'),
        winHeight = $(window).height(),
        posArr = [];

    tiles.each(function () {
        var pos = $(this).offset().top;
        posArr[pos] = $(this);
    });

    $(window).scroll((function fadeIn() {
        var sTop = $(window).scrollTop(),
            range = posArr.slice(sTop, sTop + winHeight);
        range.forEach(function (elm) {
            elm.css('opacity', 1);
        });
        return fadeIn;
    }()));
});


In this example I've used CSS3: transition: opacity .5s ease-in; for the fade in. You need to check out how to do this with jQuery's fadeIn, if needed...

Last but not least, the onScroll event callback is somehow special. It a self-executing, self-referencing function. It is called once, when it's defined, to initially show all elements already in the viewport and then returns a reference to itself for later onScroll event calls.

Hope this could help you, even if it's some time ago, you asked this question...

Code Snippets

a[100] = 'one';
a[1000] = 'two';
for (var i = 0; i < a.length; i++) {
    console.log('iterate'); // called 1000 times
}
for (var elm in a) {
    console.log('iterate'); // called two times
}
$(document).ready(function () {
    var tiles = $('.ajax_block_product'),
        winHeight = $(window).height(),
        posArr = [];

    tiles.each(function () {
        var pos = $(this).offset().top;
        posArr[pos] = $(this);
    });

    $(window).scroll((function fadeIn() {
        var sTop = $(window).scrollTop(),
            range = posArr.slice(sTop, sTop + winHeight);
        range.forEach(function (elm) {
            elm.css('opacity', 1);
        });
        return fadeIn;
    }()));
});

Context

StackExchange Code Review Q#8700, answer score: 2

Revisions (0)

No revisions yet.