mBeierl mBeierl -4 years ago 86
CSS Question

CSS Background image, fade once loaded

I want to fade-in the "image" once it is loaded from an external url, but show a "imgPlaceholder" right from the beginning from local resources.

The HTML looks like this:

<div className="bg-img" style={imgDivStyle}></div>


The CSS looks like this:

const imgDivStyle = {
background: `url('${image}'), url('${imgPlaceholder}')`,
backgroundSize: 'cover',
};


What I want to happen: Show "imgPlaceholder" from beginning and Fade-in "image" once it is loaded.

What is actually happening: "imgPlaceholder" is shown from beginning "image" is showing up instantly once it is loaded.

Is this achievable by pure CSS? Or do I need to load in the image using e.g. jQuery and trigger an animation manually?

Answer Source

You can't check if the image has loaded with css alone so you could do something like the following (comments in code to show what is happening):

$('.inner').each(function() {
  var div = $(this),
    background = div.data('background');  // get background

  $('<img/>').attr('src', background).load(function() {  // create an image element with inner background and load it
    $(this).remove();  // remove it
    
    // set the inner background image and fade in:
    div.css('background-image', 'url(' + background + ')').delay(200).fadeIn(2000); // need a little delay to let the div render it's bg image before the fade starts
  });
});
.default,
.inner {
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
  
  /* just make sure inner div is same size as outer */
  width: 400px;
  height: 400px;
}

.default {
  background-image: url(https://lorempixel.com/900/900/city/1/); /* default background */
}

.inner {
  display:none; /* start of hidden */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="default"><!-- default div with default background image -->
  <div class="inner" data-background="https://lorempixel.com/900/900/city/2/"><!-- inner div with background-image set as data attribute -->

  </div>
</div>

If you want to create the inner div on the fly, you can do something like this:

$('.background').each(function() {
  var div = $(this),
    background = div.data('background'), // get background
    html = div.html();  // get any contents

  $('<img/>').attr('src', background).load(function() {  // create an image element with inner background and load it
    $(this).remove();  // remove it
    div.empty();       // empty current div
    
    // create an inner div:
    $('<div/>')
      .css({
        'background-image': 'url(' + background + ')',
        'display': 'none'
      })                  // add background and hide
      .addClass('inner')      
      .html(html)           
      .appendTo(div)      // append to default div
      .delay(175)
      .fadeIn(2000); // need a little delay to let the div render it's bg image before the fade starts
  });
});
.background,
.inner {
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}

.background {
  background-image: url(https://lorempixel.com/900/900/city/1/); /* default background */
  
  /* just make sure inner div is same size as outer */
  width: 400px;
  height: 400px;
}

.inner {width:100%; height:100%;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="background" data-background="https://lorempixel.com/900/900/city/2/"><!-- default div with default background image,  new background image set as data attribute -->
</div>

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download