Question

I have some articles, each of them containig a list with multiple list items. Every list item has a background-image defined. The HTML looks something like this:

<article>
  <ul>
    <li><!-- background-image--></li>
    <li><!-- background-image--></li>
  </ul>
</article>

I would like to hide those list items until every image is loaded and im trying to do so for each article.

My first attempt was to use two nested loops but it feels a bit akward and complicated.

function preloader() {

    $('article').each( function(i) {        

        $(this).addClass('loading');

        var childNum = $(this).find('ul li').size();

        $(this).find('ul li').each( function(n) {

            var bgurl = $(this).css('background-image').replace(/url\(|\)|"|'/g,'');

            $('<img/>').attr('src', bgurl).load(function() {

                if (n == childNum) {

                    // remove class .loading from current article
                }

            });                             
            n++;
        });
    });
}

Is there a more elegant way of doing this ?

Was it helpful?

Solution

Just start them with visibility:hidden and show them when the window.load event fires.

CSS

.loading li{
    visibility:hidden;
}

HTML

<article class="loading">
  <ul>
    <li><!-- background-image--></li>
    <li><!-- background-image--></li>
  </ul>
</article>

and jQuery

$(window).load(function(){
   $('article.loading').removeClass('loading');
});

If you want to show the images in each article as its own images have loaded then your code is pretty close, but you can improve with the following

  • handle the error event as well
  • cache your selections
  • bind the load and error events before setting the src to correctly handle cached images

Here is an implementation

$(function () {
    var articles = $('article').addClass('loading');
    var urlRegExp = /(url\([\'\"]?)([^\'\"]+)/gi;

    articles.each(function(){
        var article = $(this),
            images = $('li', article).map(function(){
                return $(this).css('background-image').split(urlRegExp)[2];
            }).get(),
            imageCount = images.length;

        $.each(images, function(index, url){
           var img = new Image();
            $(img).on('load error', function(){
                imageCount--;
                if (imageCount === 0){
                    article.removeClass('loading');
                }
            })[0].src = url;
        });

    });
});

Demo at http://jsfiddle.net/gaby/2ATHQ/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top