简体   繁体   中英

How to improve image cross-fade performance?

I want to be able to do a cross fade transition on large images whose width is set to 100% of the screen. I have a working example of what I want to accomplish. However, when I test it out on various browsers and various computers I don't get a buttery-smooth transition everywhere.

See demo on jsFiddle: http://jsfiddle.net/vrD2C/

See on Amazon S3: http://imagefader.s3.amazonaws.com/index.htm

I want to know how to improve the performance. Here's the function that actually does the image swap:

function swapImage(oldImg, newImg) {
    newImg.css({
        "display": "block",
        "z-index": 2,
        "opacity": 0
    })
    .removeClass("shadow")
    .animate({ "opacity": 1 }, 500, function () {
        if (oldImg) {
            oldImg.hide();
        }
        newImg.addClass("shadow").css("z-index", 1);
    });
}

Is using jQuery animate() to change the opacity a bad way to go?

You might want to look into CSS3 Transitions, as the browser might be able to optimize that better than Javascript directly setting the attributes in a loop. This seems to be a pretty good start for it:

http://robertnyman.com/2010/04/27/using-css3-transitions-to-create-rich-effects/

I'm not sure if this will help optimize your performance as I am currently using IE9 on an amped up machine and even if I put the browser into IE7 or 8 document mode, the JavaScript doesn't falter with your current code. However, you might consider making the following optimizations to the code.

Unclutter the contents of the main photo stage by placing all your photos in a hidden container you could give an id of "queue" or something similar, making the DOM do the work of storing and ordering the images you are not currently displaying for you. This will also leave the browser only working with two visible images at any given time, giving it less to consider as far as stacking context, positioning, and so on.

Rewrite the code to use an event trigger and bind the fade-in handling to the event, calling the first image in the queue's event once the current transition is complete. I find this method is more well-behaved for cycling animation than some timeout-managed scripts. An example of how to do this follows:

// Bind a custom event to each image called "transition"
$("#queue img").bind("transition", function() {
    $(this)
        // Hide the image
        .hide()

        // Move it to the visible stage
        .appendTo("#photos")

        // Delay the upcoming animation by the desired value
        .delay(2500)

        // Slowly fade the image in
        .fadeIn("slow", function() {

            // Animation callback
            $(this)

                // Add a shadow class to this image
                .addClass("shadow")

            // Select the replaced image
            .siblings("img")

                // Remove its shadow class
                .removeClass("shadow")

                // Move it to the back of the image queue container
                .appendTo("#queue");

            // Trigger the transition event on the next image in the queue
            $("#queue img:first").trigger("transition");

        });   
}).first().addClass("shadow").trigger("transition"); // Fire the initial event

Try this working demo in your problem browsers and let me know if the performance is still poor.

I had the same problem too. I just preloaded my images and the transitions became smooth again.

The point is that IE is not W3C compliant, but +1 with ctcherry as using css is the most efficient way for smooth transitions.

Then there are the javascript coded solutions, either using js straight (but need some efforts are needed to comply with W3C Vs browsers), or using libs like JQuery or Mootools.

Here is a good javascript coded example (See demo online) compliant to your needs :

var Fondu = function(classe_img){
this.classe_img = classe_img;
    this.courant = 0;
this.coeff = 100;
this.collection = this.getImages();
this.collection[0].style.zIndex = 100;
this.total = this.collection.length - 1;
this.encours = false;
}
Fondu.prototype.getImages = function(){
var tmp = [];
if(document.getElementsByClassName){
    tmp = document.getElementsByClassName(this.classe_img);
}
else{
    var i=0;
    while(document.getElementsByTagName('*')[i]){
        if(document.getElementsByTagName('*')[i].className.indexOf(this.classe_img) > -1){
            tmp.push(document.getElementsByTagName('*')[i]);
        }
        i++;
    }
}
var j=tmp.length;
while(j--){
    if(tmp[j].filters){
        tmp[j].style.width = tmp[j].style.width || tmp[j].offsetWidth+'px';
        tmp[j].style.filter = 'alpha(opacity=100)';
        tmp[j].opaque = tmp[j].filters[0];
        this.coeff = 1;
    }
    else{
        tmp[j].opaque = tmp[j].style;
    }
}
return tmp;
}
Fondu.prototype.change = function(sens){
if(this.encours){
    return false;
}
var prevObj = this.collection[this.courant];
this.encours = true;
if(sens){
    this.courant++;
    if(this.courant>this.total){
        this.courant = 0;
    }
}
else{
    this.courant--;
    if(this.courant<0){
        this.courant = this.total;
    }
}
var nextObj = this.collection[this.courant];
nextObj.style.zIndex = 50;
var tmpOp = 100;
var that = this;
var timer = setInterval(function(){
    if(tmpOp<0){
        clearInterval(timer);
        timer = null;
        prevObj.opaque.opacity = 0;
        nextObj.style.zIndex = 100;
        prevObj.style.zIndex = 0;
        prevObj.opaque.opacity = 100 / that.coeff;
        that.encours = false;
    }
    else{
        prevObj.opaque.opacity = tmpOp / that.coeff;
        tmpOp -= 5;
    }
}, 25);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM