Search code examples
jquerycssjquery-uigoogle-chromebackground-size

How to optimize an image sequence in Chrome?


On a website, I have a slider (I'm using jQuery UI's slider) that is used to control an image sequence. The images are displayed full screen in the background of the page (I'm using background-size: cover). On my development PC, it's working perfectly but when I try it on less powerful computers, it's laggy.

The way I do my sequence is quite simple. Here's some of my code to give a general idea of what I'm doing. (I think that code is not essential for my question, but I added it anyway... Feel free to skip ahead!)

HTML:

<div id="animation">
    <div class="frame frame0"></div>
    <div class="frame frame1"></div>
    <div class="frame frame2"></div>
    [...]
    <div class="frame frame20"></div>
</div>

CSS:

#animation {
    height: 100%;
    position: relative;
    width: 100%;
}
#animation div.frame {
    background-position: center center;
    background-size: cover;
    bottom: 0;
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
    z-index: 1;
}
#animation div.frame.active { z-index: 2; }
#animation div.frame0 { background-image: url(frame0.jpg); }
#animation div.frame1 { background-image: url(frame1.jpg); }
[...]
#animation div.frame20 { background-image: url(frame20.jpg); }

jQuery:

var $frames = $('#animation').find('div.frame');
$('#slider').slider({
    value: 1,
    min: 1,
    max: 21,
    step: 1,
    slide: function(event, ui){
        $frames.removeClass('active').filter(':eq(' + (ui.value - 1) + ')').addClass('active');
    }
});

By testing different things, I managed to isolate what it causing performance issues in Chrome. The culprit is background-size: cover. As soon as I remove the background-size attribute and use the images default size, I have close to no lag.

When I use background-size: cover and my images are about the same size as my Chrome window, the performance is better. But the larger the images are stretched (or compressed) relative to the original image size, the more lag I get.

The only lead I have so far to optimize this is to have different image sizes and use JavaScript to load the sequence in the size that is closer to the browser window and hope that it won't be laggy. And this mean that I may have to reload another image kit if the user resizes the browser window.

Any idea how I could optimize the image sequence in Chrome to get better performance?


Solution

  • I did a test today using a canvas instead of a list of HTML elements for each frame. It results in a very good performance in Chrome. The downside of the the canvas solution is that it's not working in IE8 but for this project, we have a lot more users on Chrome than on IE8 so I can live with that.

    This helped me with the canvas drawing: Frame by frame animation in HTML5 with canvas

    And the rest was to simply modify the canvas on the slider change instead of adding and removing the active class.

    var arrFrames = [];
    for(var i = 0; i < 21; i++){
        arrFrames[i] = new Image();
        arrFrames[i].onload = function() { /* check that all images are loaded before allowing the animation on the slider */ }
        arrFrames[i].src = 'frame' + i + '.jpg';
    }
    
    $('#slider').slider({
        value: 0,
        min: 0,
        max: 20,
        step: 1,
        slide: function(event, ui){
            /* Calculate image size and ratio */
            ctx.clearRect(0, 0, iCanvasWidth, iCanvasHeight);
            ctx.drawImage(arrFrames[ui.value], 0, 0, iWidth, iHeight);
        }
    });
    

    I didn't put all variable definitions in the code to keep it short and clean, but the variable names should be clear enough to understand what value they have.

    One important thing I realized: don't forget to set width and height for the canvas in javascript. Setting it only in CSS will only stretch it.