1

The following code creates the effect when one image goes to white and then white is changed with another image (demo):

HTML:

<body>
    <div class="page-bg" id="page-background1"></div>
    <!-- <div class="page-bg" id="page-background2"></div> -->
</body>

JavaScript:

url = "http://example.com/picture.png";

$("#page-background1")
    .animate({
    opacity: 0
}, 'slow', function () {
    $("#page-background1")
        .css({
        'background-image': 'url(' + url + ')'
    })
        .animate({
        opacity: 1
    });
});

But I would like to change one image directly with another (without white color in between), but with fadeOut/fadeIn effect. How should I do it? Looks like usage of the second div should help, but I can not find working solution.

LA_
  • 19,823
  • 58
  • 172
  • 308

3 Answers3

1

Updated, I tried to apply Stacking elements with Z-index to get the desired effect. I also created a kind of "stack" of images where z-index is changed for the image that was hidden; the most recently hidden element is changed for a smaller z-index value in comparison to other images in the "stack". The code supports multiple images in the photos array, because it creates an individual div for each image.

var photos = [{
  url: 'https://drscdn.500px.org/photo/97037403/m=900/d924fc03d69a82a604129011300916be'
}, {
  url: 'https://drscdn.500px.org/photo/97037259/m=900/030e1598b7822cd6c41beb4c7a4e466d'
}, {
  url: 'https://drscdn.500px.org/photo/97158643/m=900/4ae40d67ef546341111a32f5176694c8'
}];

//z-index, start value -1
//z-index can be either positive or negative value
//based on this answer http://stackoverflow.com/a/491105/2048391
var zIndex = -1;

//first foto in the array shown/hidden first
var visibleIndex = 0;

//initialize 
//by creating div for each image/url
for (i = 0; i < photos.length; i++) {
  var div = document.createElement("div");
  div.id = "page-background" + (i + 1);
  div.setAttribute("class", "page-bg");
  div.style.zIndex = zIndex;
  var url = "url('" + photos[i].url + "')";
  div.style.background = "#505D6E " + url + " no-repeat center center fixed";
  document.body.appendChild(div);
  zIndex = zIndex - 1;
  //and add div id to the photos array
  photos[i].id = "page-background" + (i + 1);
}


function changeBackground() {
  var hideItemIndex = visibleIndex % photos.length;
  var showItemIndex = (visibleIndex + 1) % photos.length;

  var hideItemId = "#" + photos[hideItemIndex].id;
  var showItemId = "#" + photos[showItemIndex].id;

  //hide current image with animation
  //after which show the next image with animation
  $(hideItemId).animate({
    opacity: 0
  }, "slow", function() {
    $(showItemId)
      .animate({
        opacity: 1
      }, "slow");

    //change z-index for the item that was hidden 
    //by moving it to the bottom of the stack
    $(hideItemId).css("z-index", zIndex);
    $(hideItemId).css("opacity", 1);

  });

  zIndex = zIndex - 1;

  visibleIndex = visibleIndex + 1;
}

//make sure that there's at least 2 images in the array
if (photos.length > 1) {
  setInterval(function() {
    changeBackground();
  }, 2000);
}
.page-bg {
  border: 1px solid black;
  height: 100%;
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  -webkit-background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  background-size: cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

Alternative way of doing the same thing as above. Below only visible and the next div element exist, and the hidden div is removed for performance reasons, like suggested by LA_

var photos = [{
    url: 'https://drscdn.500px.org/photo/97037403/m=900/d924fc03d69a82a604129011300916be'
}, {
    url: 'https://drscdn.500px.org/photo/97037259/m=900/030e1598b7822cd6c41beb4c7a4e466d'
}, {
    url: 'https://drscdn.500px.org/photo/97158643/m=900/4ae40d67ef546341111a32f5176694c8'
}];

//z-index, start value 100000
//z-index could be a larger number
//based on this answer http://stackoverflow.com/a/491105/2048391
var zIndex = -1;

//first foto in the array shown/hidden first
var visibleIndex = 0;

//initialize 
//by creating div for each image/url
for (i = 0; i < photos.length; i++) {
    
    //only two images are created
    if (i < 2)
       createDiv(i, (i + 1) );

    //and add div id to the photos array
    photos[i].id = "page-background" + (i + 1);
}

function changeBackground() {
    var hideItemIndex = visibleIndex % photos.length;
    var showItemIndex = (visibleIndex + 1) % photos.length;
    
    var hideItemId = "#" + photos[hideItemIndex].id;
    var showItemId = "#" + photos[showItemIndex].id;

    //hide current image with animation
    //after which show the next image with animation
    $(hideItemId).animate({
        opacity: 0
    }, "slow", function () {
        $(showItemId)
            .animate({
            opacity: 1
        }, "slow");

        //remove the item that was hidden 
        $(hideItemId).remove();

    });
    
    var nextItemIndex = (visibleIndex + 2) % photos.length;
    //create the next div with picture
    createDiv(nextItemIndex, (nextItemIndex + 1) );

    visibleIndex = visibleIndex + 1;

}

//make sure that there is at least 2 photos 
if (photos.length > 1) {
    setInterval(function () {
        changeBackground();
    }, 2000);
}

function createDiv(index, divIdNro) {
      
    var div = document.createElement("div");
    div.id = "page-background" + divIdNro;
    div.setAttribute("class", "page-bg");
    div.style.zIndex = zIndex;
    var url = "url('" + photos[index].url + "')";
    //div.style.backgroundImage = url;
    div.style.background = "#505D6E " + url + " no-repeat center center fixed";
    document.body.appendChild(div);
    
    zIndex = zIndex - 1;    
}
.page-bg {
    border:1px solid black;
    height:100%;
    width: 100%;
    position: absolute;
    top: 0;
    left: 0;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
jyrkim
  • 2,849
  • 1
  • 24
  • 33
  • Thanks. But I can not get it working, when more than one change of background should happen - please see http://jsfiddle.net/and7ey/eq5m7nev/9/. – LA_ Jan 29 '15 at 18:12
  • @LA_ Hi, I think, I finally got it working. Now it handles multiple images in dynamic way as each image is given an individual div. Fiddle: http://jsfiddle.net/jyrkim/eq5m7nev/13/ – jyrkim Jan 30 '15 at 08:25
  • Many thanks. Now I've got two more questions. (1) Usage of such high value `z-index` requires either element (like texts and buttons) to have even bigger `z-index` value. Looks like I can use negative `z-index` value for **background** picture. Why haven't you used it? (2) If I have 20 images, then looks like all of them are stored in the memory. Shouldn't I somehow destroy previous div element once new div is shown? – LA_ Jan 30 '15 at 09:37
  • @LA_ Good point! I just tested and it works with negative integers as well. I think using negative integers is probably the smart way of doing it, especially when the image is on the background. I’m going to update my answer, and set the z-index start value to -1 --> zIndex = -1. Thanks for point out that issue :-) – jyrkim Jan 30 '15 at 10:40
  • @LA_ Your second question about adding and removing div elements, I think that could work too. I think that alternative is worthwhile and probably better than the current one. Like you said, if there are a lot of images it could be more useful for performance reasons. Anyway, I tested with 24 images (that had 24 divs), and it worked also: http://jsfiddle.net/jyrkim/eq5m7nev/14/ Now, I am thinking whether try out the alternative you suggested :-) – jyrkim Jan 30 '15 at 10:42
  • @LA_ Here you go a fiddle with the changes you suggested in the 2nd question: http://jsfiddle.net/jyrkim/2nzpgye4/3/ – jyrkim Jan 30 '15 at 11:12
  • Thanks a lot for your help! I've simplified the code a little - http://jsfiddle.net/and7ey/2nzpgye4/7/ (just in case someone else will use the solution) – LA_ Jan 30 '15 at 17:09
  • @LA_ My pleasure :-) Overall, a great experience. It was the first time I've made some visual effects with JavaScript; so it was very useful experience for me. – jyrkim Jan 30 '15 at 21:37
  • @LA_ Hi, I have looked into this issue again, it feels that I've almost just started - well just kidding :-) but I just discovered a couple of alternative ways of doing the opacity effect and those alternatives look very sound indeed: http://stackoverflow.com/a/20923131/2048391 In that link is my favorite way of doing the opacity change with combination of jQuery and CSS transitions and it looks cool. There is another alternative that uses a bit more code; it can be found above the answer in the previously mentioned link, but overall they look quite similar. – jyrkim Feb 01 '15 at 13:51
  • It is not quite clear what is the advantage of usage of that CSS way compared to what you've done. Moreover, our approach already considers that many-many images could be used. – LA_ Feb 01 '15 at 13:57
  • @LA_ A good point, the link that I passed had 2 seconds set for opacity transition which looked good. Consequently, I tested with 2 seconds in the changeBackground() function and it looked good too :-) So I guess it was just a matter of adjusting the time that it takes to change the opacity. So both answers are quite similar from visual perspective (which I thought was different 15 mins ago) – jyrkim Feb 01 '15 at 14:05
0

here's a fiddle as snippets not working sat the mo, you can put the speed of the fade in milliseconds or keyword, it's at slow. I've left it on button click and not passed in the url but take out my button click function and put the code into your setinterval func, also set the url in jquery back to url variable

$('button').on('click',function(){
   $("#page-background1").fadeOut( "slow", function() {
    $("#page-background1")
        .css({
        'background-image': 'url(http://lorempixel.com/400/400/sports/2)'
        });});
    $("#page-background1").fadeIn('slow');
});
.page-bg{
    min-width:500px;
    min-height:500px;
}
#page-background1{
        background-image: url(http://lorempixel.com/400/400/sports/1);
    background-size:400px 400px;
    background-repeat: no-repeat;
    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click me to change the background</button>
<div class="page-bg" id="page-background1">;</div>
Billy
  • 2,448
  • 1
  • 10
  • 13
  • Ah, sorry, looks like I should re-phrase my question - I would like to change one image with another with fadeOut/fadeIn effect. – LA_ Jan 29 '15 at 10:13
  • give me a sec to do a fiddle,for some reason getting a 500 error on stack snippets. what do you want to trigger the change ? – Billy Jan 29 '15 at 10:15
  • I use `setInterval()`, since I change background images one by one from the `photos` array, `photosNext` keeps id of the image to be shown next. – LA_ Jan 29 '15 at 10:17
  • Thanks. But do you see any difference to what I've shown in my question? It works exactly in the same way, I think - the first image fades out to white, then the second images fades in. You just use `fadeIn`/`fadeOut` and I used `opacity`. – LA_ Jan 29 '15 at 16:46
0

Change the javascript to:

url = "http://example.com/picture.png";
    .animate({
    opacity: 0.5
}, 'fast', function () {
    $("#page-background1")
        .css({
        'background-image': 'url(' + url + ')'
    })
        .animate({
        opacity: 1
    });
});
Dawn T Cherian
  • 4,968
  • 3
  • 24
  • 35