Tackling Safari’s slow gif “feature” with jQuery

Safari’s WebKit has a funny behav­ior of dis­play­ing ani­mated gif files at a lower frame rate than Firefox. From what I can tell, WebKit (includ­ing Google Chrome) caps the ani­mated gif frame rates at 10fps. While it may be faster than some IE6 browsers, it’s not exactly help­ful for those files with higher frame rates.

For exam­ple, the pop­u­lar ajax loader file that hails from Apple’s own asyn­chro­nous progress indi­ca­tor, has 12 points and loops around once a sec­ond. Well, for one thing, 12fps is really choppy, but it already plays slower on Apple’s nifty browser.

jQuery to the rescue

Did you know that jQuery can con­trol css back­ground posi­tions? Are you think­ing what I’m think­ing?

But first, back to draw­ing board

So the first part was to break up the ani­mated gif frames and spread them out across a very long can­vas. Since Photoshop no longer opens ani­mated gif files (unless you own ImageReady some­where), Fireworks can open the file. Use Fireworks to export the frames to indi­vid­ual files and THEN Photoshop can import all the files as a stack.

File <Scripts> Load Files into Stack…

For our ajax loader, expand all the lay­ers next to each other and then save it out to its own gif. The file size won’t be that dif­fer­ence in fact.

Now let’s get back to jQuery

In our html, just set the div with a width and height to match your gif to pre­vent clip­ping and let the script do the rest.


$(document).ready(function(){
	var bgimage = 'url(images/ajax-loader-long.gif)';
	var frames = 24;
	var mpf = parseInt(1000/frames)  // how many miliseconds in each frame
	var currentFrame = 0;
	var offset = 0;

	$('.animate').css('background-image', bgimage);

	function animate() {
		offset = currentFrame * 64;
		$('.animate').css('background-position', '-' + offset + 'px 0px');
		currentFrame = (currentFrame == frames) ? 1 : currentFrame + 1;
	}

	setInterval(animate, mpf);
});

Now we have a script that will snap the posi­tion of the back­ground over each “frame” at the cor­rect frame rate. Actually, the frame rate is not divis­i­ble by 1000, but it’s close and it’s not like you could tell.

The only prob­lem with this script is that it’s con­stantly run­ning. If you look at the page in Firebug, your going to see the code whip­ping around with new val­ues all the time. Annoying! Also, chances are your page isn’t going to need some ani­ma­tion play­ing con­stantly. Ajax load­ers are inter­mit­tently called when a sim­ple action is called as a… asyn­chro­nous progress indi­ca­tor! Who knew.

So we’re going to put in a can­cel com­mand to this script: clearTime­out.


$(document).ready(function(){
	var bgimage = 'url(images/ajax-loader-long.gif)';
	var frames = 24;
	var mpf = parseInt(1000/frames)  // how many miliseconds in each frame
	var currentFrame = 0;
	var offset = 0;
	var runAnimate = 0;

	$('.animate').css('background-image', bgimage);

	function animate() {
		offset = currentFrame * 64;
		$('.animate').css('background-position', '-' + offset + 'px 0px');
		currentFrame = (currentFrame == frames) ? 1 : currentFrame + 1;
	}

	runAnimate = setInterval(animate, mpf);

	$('.animate').toggle(
		function () {
			clearTimeout(runAnimate);
		},
		function () {
			runAnimate = setInterval(animate, mpf);
		}
	);
});

Add in a tog­gle so show how to turn on and off the ani­ma­tion and were done.

It even works on ie6!

This entry was posted in Code, Design and tagged , , , , , , , , . Bookmark the permalink.

Comments are closed.