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

Make an image appear on scroll event

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

Problem

I recently was playing around with the idea of having an image appear when the user scrolls and came up with the following. Is there a better or more efficient way to do it?

var pastScroll;
jQuery(document).scroll(function () {
    var currentScroll = jQuery(document).scrollTop();
    if (pastScroll == currentScroll) {
        //console.log("not moving");
        jQuery('#content').css('background-image', 'url("/onScroll/blank.png")');
        // clear background
    }
    else {
        jQuery('#content').css('background-image', 'url("/onScroll/logo.png")');
        jQuery('#content').css('background-repeat','no-repeat');
        jQuery('#content').css('background-position', 'center'); 
        //console.log('moving');
        pastScroll = currentScroll;
        setTimeout(function () {
            if (pastScroll == currentScroll) {
                //console.log("not moving");
                jQuery('#content').css('background-image', 'url("/onScroll/blank.png")');
            }
        }, 100)
    }
});


You can ignore the use of jQuery instead of $ because it's being used in wordpress and ignore the css style added. I'm just wanting to focus on the conditionals and triggering. Any constructive criticism is appreciated, thanks.

Solution

-
Use CSS to change the background image of an element. It's easy and safe than using css() to change the styles of element from JavaScript. This also keep separation of concerns. Tomorrow, if you want to change the image size, you just have to go to the CSS and update the particular CSS class.

Also, note that the three properties background-image, background-repeat and background-position can be combined into background property.

CSS:

.logo {
    background: url('/onScroll/logo.png') center no-repeat;
}
.blank {
    background: url('/onScroll/blank.png');
}


JavaScript:

$('#content')
    .addClass('logo')       // Add class
    .removeClass('blank');  // Remove class


-
Wrap the code in IIFE to avoid cluttering global namespace by creating global variables. Also, passing the variables to IIFE will create local alias reducing scope chain operations.

(function ($, document) {
     // CODE HERE
     ...
}(jQuery, document));


Note that jQuery is passed as first parameter and catch-ed in $. Less typing. More readable.

-
Cache the element references. By doing this, the elements are not needed to be taken from DOM again. Thus improving performance.

// Caching
var $document = $(document),
    $content = $('#content');


-
Use strict equality operators for comparison. See Which equals operator (== vs ===) should be used in JavaScript comparisons?

if (pastScroll === currentScroll) {


-
Chaining. jQuery provides feature to chain multiple calls on same elements.

jQuery('#content').css('background-image', 'url("/onScroll/logo.png")');
jQuery('#content').css('background-repeat','no-repeat');
jQuery('#content').css('background-position', 'center');


Instead of this, multiple calls can be chained

jQuery('#content').css('background-image', 'url("/onScroll/logo.png")')
    .css('background-repeat', 'no-repeat')
    .css('background-position', 'center');


OR better, jQuery allows to pass an object to css() where multiple styles can be set in one call.

jQuery('#content').css({
    'background-image': 'url("/onScroll/logo.png")',
    'background-repeat': 'no-repeat',
    'background-position': 'center'
});


Better way is to use CSS classes as explained in #1 above.

-
Clearing previously set timeouts, if any.

As setTimeout is used, if user keeps scrolling continuously the timeout callback will be executed multiple number of times. This is not really required. You can use clearTimeout to clear previously set timeouts, thus only one timeout will be executed once user has stopped scrolling and 100 ms is passed.

Complete Code:

CSS:

.logo {
    background: url('/onScroll/logo.png') center no-repeat;
}
.blank {
    background: url('/onScroll/blank.png');
}


JavaScript:

// Wrap the code in IIFE
(function ($, document) {
    'use strict';

    // $        = an alias for jQuery
    // document = alias for document object

    // Private variables
    var pastScroll,
        timeout;

    // Caching
    var $document = $(document),
        $content = $('#content');

    $document.scroll(function () {
        var currentScroll = $document.scrollTop();

        // Use strict equality operator
        if (pastScroll === currentScroll) {
            // For multiple method calls on same element, use chaining
            // Use CSS class to set the background image
            $content.addClass('blank').removeClass('logo');
        } else {
            $content.addClass('logo').removeClass('blank');

            pastScroll = currentScroll;

            // Clear previous timeouts
            clearTimeout(timeout);
            timeout = setTimeout(function () {
                if (pastScroll === currentScroll) {
                    $content.addClass('blank').removeClass('logo');
                }
            }, 100);
        }
    });
}(jQuery, document));

Code Snippets

.logo {
    background: url('/onScroll/logo.png') center no-repeat;
}
.blank {
    background: url('/onScroll/blank.png');
}
$('#content')
    .addClass('logo')       // Add class
    .removeClass('blank');  // Remove class
(function ($, document) {
     // CODE HERE
     ...
}(jQuery, document));
// Caching
var $document = $(document),
    $content = $('#content');
if (pastScroll === currentScroll) {

Context

StackExchange Code Review Q#140210, answer score: 4

Revisions (0)

No revisions yet.