What's the best way to cycle through a large number of fixed position images in WebKit efficiently? What's the best way to cycle through a large number of fixed position images in WebKit efficiently? google-chrome google-chrome

What's the best way to cycle through a large number of fixed position images in WebKit efficiently?


You can debug the page performance in Chrome using the Timeline tab under the Chrome developer tools. The problem with your script is that your repaint cycle is simply too expensive, it currently takes 1.35s to repaint every frame.

enter image description here

The bad performance has nothing to do with the quality of the jpeg images (although the image quality also affects the page render time). The problem is that you are updating the z-index which causes the Chrome to repaint all images instead of just the next frame (You have a O(n) image slider website!).

The browsers try to do the minimal possible actions in response to a change e.g.: changes to an elements color will cause only repaint of the element.

Changing the element z-index property is basically the same as removing a node from the tree and adding another node to it. This will cause layout and repaint of the element, its children and possibly siblings. My guess is that in Chrome, the siblings are being repainted too, this explains the horrible performance.

A way to fix this problem is to update the opacity property instead of the z-index. Unlike the z-index, the opacity does not modifies the DOM tree. It only tells the render to ignore that element. The element is still 'physically' present in the DOM. That means that only one element gets repainted and not all siblings and children.

This simple changes in your CSS should do the trick:

.making-of .slide#slide-top {   opacity: 1;   /* z-index: 5000; */}.making-of .slide {   position: fixed;   /* z-index: 4000; */   opacity: 0;   ....}

And this is the result, the repaint went from 1.35s to 1ms:

enter image description here

EDIT:

Here is a jsfiddle using the opacity solution, I also added CSS3 transitions (just for fun!)

http://jsfiddle.net/KN7Y5/3/

More info on how the browser rendering works:

http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/


I took a look at the code on your site and found two things that are limiting the speed.

1) In the JavaScript, you have a timeout of approximately 1/4 second (244 milliseconds). This means that your best-cast frame-rate is about 4 FPS (frames-per-second). This can be fixed by simply reducing the delay to match the frame rate that you actually want. I see that your most recent edit addresses this point, but I didn't want to ignore it since it is ultimately critical to achieving the higher frame-rates that you want.

2) You are using z-index to control which image is visible. In the general case, z-index handling allows for objects that have different sizes and positions to be ordered so that you can control which object is visible at locations where two or more objects overlap. In your case, all of the objects overlap perfectly, and the z-index approach works fine except for one major problem: browsers don't optimize z-index processing for this case and therefore they are actually processing every image on every frame. I verified this by creating a modified version of your demo which used twice as many images -- the FPS was reduced by nearly a factor of 2 (in other words, it took 4 times as long to display the entire set).

I hacked together an alternative approach that achieved a much higher FPS (60 or more) under both Chrome and Firefox. The gist of it was that I used the display property instead of manipulating z-index:

.making-of .slide#other {   display: none;}.making-of .slide#slide-top {   display: inline;}

and the JavaScript:

function nextSlide() {  ...  topSlide.id='other';  nextTopSlide.id='slide-top';  ...  setTimeout(nextSlide, 1);  ...}

I made some changes in the HTML too, notably including id="other" in the tag for each image.


So why is WebKit so slow? As has been pointed out in other comments, the extra-poor performance that you are seeing on Webkit seems to be Mac specific. My best guess about this is that the Mac version of WebKit is not actually using the "turbo" version of libjpeg (despite the fact that it is listed in the credits). In your test, JPEG decompression could very well be the gating factor if it is actually decompressing every image on every frame (as is likely the case). Benchmarking of libjpeg-turbo has shown about a 5x improvement in decompression speed. This roughly matches the difference that you are seeing between Firefox and Chrome (3 FPS vs. 0.6795 FPS).

For more notes on libjpeg-turbo and how this hypothesis explains some of your other results, see my other answer.


Key in my experience is to keep as less as possible images in the DOM and in javascript arrays, so don't load all of the at once, keep it to a minimum. Also make sure you destroyed already used DOM elements as well as javascript objects holding images, manual garbage collection. This will improve performance.