5

I'm working on a site that is very background-image intensive. Since some of the images are large, the aesthetic appeal of the page will inevitably suffer at the initial load, probably for several seconds.

So I'm trying to make a background-image preloader with jQuery and here's where I'm at:

$(document).ready(function(e){
  $('*')
    .each(function(){
        if($(this).css('background-image') != 'none'){

            //so, i can get the path, where do i go from here?
            alert($(this).css('background-image').slice(5, -2));

        }
    });
});

I'm used an array of Image() objects, to load the image using the path pulled from my iterator, but I'm lost on where to go from here.

How can I determine when all of the images in the array have 'loaded', so that I can call a function to fade out a preloader curtain or something?

4 Answers 4

3

You should be able to pull off something like this (untested!):

$(document).ready(function(e){

   // get a collection of all elements with a BG image
   var bgImages = $('*').filter(function(){
       return $(this).css('background-image') != 'none');

   // get a collection of new images, assigning the sources from the original collection
   }).map(function() {
       return $("<img />").attr("src", $(this).css('background-image').slice(5, -2));
   });

   var len = bgImages.length;
   var loadCounter = 0;

   // use an onload counter to keep track of which ones have loaded
   bgImages.load(function() {
      loadCounter++;
      if(loadCounter == len) {

         // we have all loaded
         // fade out curtain
      }
   }).each(function() {

      // if we have been pulled up from cache, manually trigger onload
      if (this.complete) $(this).trigger("load");
   });
});
Sign up to request clarification or add additional context in comments.

5 Comments

I have to head out for about half an hour, so I won't be able to respond during that time.
have you thought about just using progressive JPGs, so that they display low quality and get better as they load?
@Nilloc: Yes, but for this implementation, a preloader is almost necessary to maintain the aesthetic appeal of the site/page. Progressive loading would make it look progressively less crappy :)
I really liked this unfortunately in Chrome it doesn't seem to fire off inside the bgImages.load function
Safari acts the same as chrome too
1

Here are a few resources to look at:

If you use a DOM element instead of Image you can watch the image onload callback

var path = $(this).css('background-image').slice(5, -2);
var img = document.createElement('img');
img.src = path;
$(img).load(function(){ /* incrament counter for loaded images */})

Comments

1
   // Get all backgrounds
   var bgImages = $('*').filter(function()
   {
       return ($(this).css('background-image') != 'none');
   })
   // Create IMG objects for it
   .map(function()
   {
       // Works in Chrome!!! Chrome not uses brackets near url()
       return $('<img />').attr('src', $(this).css('background-image').replace(/\url|\(|\"|\"|\'|\)/g, '')); 
   });

   var len = bgImages.length;
   var loadCounter = 0;

   $(bgImages).each(function()
   {
        $(this).load(function()
        {
            loadCounter++;
            console.log(loadCounter); // Look at console 
            if(loadCounter == len) { // ALL LOADED!!! }
        });
    })
    // Cached trigger
   .each(function()
    {
        if (this.complete) $(this).trigger('load');
    });

Comments

0

Thanks to karim79 and Josiah Ruddell. I've solved it for the time being, using a bit of a hybrid from suggestions and trial and error:

    var preloaderTotal = 0;
    var preloaderLoaded = 0;
    var preloaderCurrent = null;

    $('#preloaderCurtain')
        .bind('preloaderStart', function(){
            $(this)
                .show();
            $('*')
                .filter(function(e){
                    if($(this).css('background-image') != 'none'){
                        preloaderTotal++;
                        return true;
                    }
                })
                .each(function(index){
                    preloaderCurrent = new Image();
                    preloaderCurrent.src = $(this).css('background-image').slice(5, -2);
                    preloaderCurrent.onload = function(e){
                        preloaderLoaded++;
                        if(preloaderLoaded == preloaderTotal - 1){
                            $('#preloaderCurtain')
                                .trigger('preloaderComplete')
                        }
                        $('#preloaderCurtain')
                            .trigger('preloaderProgress')
                    };
                });
        })
        .bind('preloaderComplete', function(){
            $(this)
                .fadeOut(500)
            startAnimation();
        })
        .bind('preloaderProgress', function(e){
            $('#preloaderProgress')
                .css('opacity', 0.25 + (preloaderLoaded / preloaderTotal))
                .text(Math.floor((preloaderLoaded / preloaderTotal) * 100) + '%');
        })
        .trigger('preloaderStart');

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.