views:

792

answers:

2

I'm trying to do a simple rotating image on the home page. Under the hood I'm reading a directory and then populating urls for the images into an array. What I want to do is cross-fade the images. If it was just a matter of showing the next one, it's easy, but since I need to cross-fade, it's a bit harder. I think what I want to do is do the fades by calling animate() on the opacity value of the <img> tag, and in between swapping out the css background-image property of the enclosing <div>. But the results are not that great.

I've used tools for more full featured slideshows, but I don't want the overhead of adding a plugin if I can avoid it, and a simple crossfade seems like it should be easier.

Here's my JavaScript (I'm using jQuery 1.3.2):

var slideshow_images = ["http:\/\/example.com\/wordpress\/wp-content\/themes\/testtheme\/sidebar-home-bg\/bg1.jpg","http:\/\/example.com\/wordpress\/wp-content\/themes\/testtheme\/sidebar-home-bg\/bg2.jpg","http:\/\/example.com\/wordpress\/wp-content\/themes\/testtheme\/sidebar-home-bg\/bg3.jpg"];
var slideshow_index = 0;
var delay = 4000;
var swapSlides = function() {
 var slideshow_count = slideshow_images.length;
 // initialize the background to be the current image
 $('#home-slideshow').css({
  'background-image': 'url(' + slideshow_images[slideshow_index] + ')',
  'background-repeat:': 'no-repeat',
  'width': 200,
  'overflow': 'hidden'
 });
 slideshow_index = ((slideshow_index + 1) == slideshow_count) ? 0 : slideshow_index + 1;
 // fade out the img
 $('#home-slideshow img').animate({opacity: 0}, delay);
 // now, the background is visible
 // next change the url on the img
 $('#home-slideshow img').attr('src', slideshow_images[slideshow_index]);
 // and fade it up
 $('#home-slideshow img').animate({opacity: 1.0}, delay);
 // do it again
 setTimeout('swapSlides()', 4000);
}


jQuery(document).ready(function(){ 
 if (swapSlides) {
  swapSlides();
 }
});

And here's the markup I'm using:

<div id="home-slideshow"><img src="http://example.com/wordpress/wp-content/themes/testtheme/sidebar-home-bg/bg1.jpg" alt="" /></div> 
+1  A: 

The first thing that you should be aware of and that must be causing problems with your code : the animate methods are not synchronous ! So when you do :

$('#home-slideshow img').animate({opacity: 0}, delay);
 // now, the background is visible
 // next change the url on the img
 $('#home-slideshow img').attr('src', slideshow_images[slideshow_index]);

You start to animate, but the method immediately returns. You can imagine the animation as a background thread , although there is no such thing as a thread in JavaScript and everything is implemented using settimeout calls.

So in your code, at the moment you change the src attribute, the image is probably still 99% visible. And then you start to animate it back to 100% opacity, but at this point it is still at say 98%, and the two "threads" will try to simultaneously make it appear/disappear !

So in your code will need to either set timeouts to execute the tasks in the correct order (always leaving a few milliseconds of margin inbetween), or, safer but maybe less readable when you have many successive function calls, use the callback function of the animate method. For example :

$('#home-slideshow img').animate({opacity: 0}, delay, function(){
    // now, the background is visible
    // next change the url on the img
    $('#home-slideshow img').attr('src', slideshow_images[slideshow_index]);
    // and fade it up
    $('#home-slideshow img').animate({opacity: 1.0}, delay, function(){
        // do it again
        setTimeout('swapSlides()', 4000);
    });
});

Finally, what you are doing is a fade-out + fade in. If you want a real cross fade you'll need to have 2 element simultaneously at some point :

  1. start : there is only one element, with opacity 100%
  2. build your new element with the right url for the background image (or use an img element)
  3. add the new element to the dom tree with opacity 0%, as a sibling to the existing one
  4. start to animate simultaneously the opacity of the current element from 100% to 0% and the opacity of the new element from 0% to 100%
  5. remove the old, now invisible element
Pierre Henry
+1  A: 

try this:

DEMO: http://jsbin.com/ipudo/7

few line of jQuery

$(function(){
    $('#home-slideshow img:gt(0)').hide();
    setInterval(function(){
      $('#home-slideshow :first-child').fadeOut()
         .next('img').fadeIn()
         .end().appendTo('#home-slideshow');}, 
      3000);
});

2 line of CSS

#home-slideshow { position:relative; height:332px; width:500px; }
#home-slideshow img { position:absolute; left:0; top:0; }​

your HTML

   <div id="home-slideshow">
      <img src="image.jpg" alt=""/>
      <img src="image.jpg" alt=""/>
      <img src="image.jpg" alt=""/>
       ...
       ...
    </div>
aSeptik