Tutorial: Color changing liquid effect with jQuery

This tutorial is on how to archieve a color changing liquid effect (like this one) with jQuery. It’s actually quite easy to implement, altough there is a small trap. It’s made with plain CSS2 and will run in every modern browser (note: I don’t consider IE6 as a “modern browser”).

LayersThe trick is to use three layers: The first is the symbol or the text, with the essential parts left transparent, the second is a gray layer with a transparent wave at the bottom an the last is a solid CSS-background-color. With some jQuery-magic to animate the second layer you can create an effect of wavy liquid.

1. Prepare your files

You will obviusly have to get an icon (You can find some usefull here) or some text to “pour” the liquid in. Use Gimp, Inkscape or any other image editor to create a white png with the relevant parts being transparent. I’ve added some inner shadow to create an illusion of depth, but that’s really up to you.

Now you have to create a png “wave” or use mine here instead. It’s a tall, gray image with only the bottom part shaped like a wave – this part has to be transparent too. You have to form the wave in a way that it fits seamlessly to itself.

Now get jQuery, the color-animation plugin (here’s the source) and a plain html file.

2. The HTML and CSS

Create all javascript-links in the header. Now add the following to the <body>:

<img src="icon.png" class="wave" id="icon" alt="Some alt-text"/>

Now add some CSS:

.wave {
	background-image: url('wave.png');
	background-repeat: repeat-x;
	background-position: 0px -160px; /* Change "-160px" until you see the wave  */
}

3. The trap

I first started to animate the background-image by changing background-position-x, but it turned out that this is (for some unknown reason and besides being very usefull) not part of the CSS-standart. So I faced the weird case that there was no problem with IE, Safari and Chrome, but with Firefox which has not implemented this attribute. I tried to write a plugin to emulate background-position-x/y for Firefox, but some odd behaviours made me go the easier (and dirtier) way.

The x-offset of the waves is now stored in a global variable called “bpx” and the y-offset is stored directly in the specific element via

// This is the global x-offset for all waves on this page
var bpx = 0;
// This is the y-position of the wave at the beginning
$('#icon')[0].bpy = -160;

An interval-function concatenates these two values every 10 miliseconds and writes them back to “background-position”:

// This code does the actual animation. It's called every 10msec
window.setInterval(function() {				
// Increase bpx and decrease reset it to 0 everytime it 
// reaches 100 (=the width of the wave-png)
bpx = (bpx+1) % 100;	
// The jQuery function "each" makes it possible to animate multiple elements 
$('.wave').each(function() {
	this.style.backgroundPosition = bpx + 'px '+this.bpy+'px';
});
}, 10);

You can now animated the “height” of the wave by simply animating the bpy-attribute like any other css-value:

$('#icon').stop().animate({bpy: -140},300);

4. Changing the color

To change the colour of the liquid randomly there is an easy way to do so with jQuery:

function changeColor(e){  
	// Generate a new color
	 var color = 'rgb(' + (Math.floor(Math.random() * 256)) + ',' 
		+ (Math.floor(Math.random() * 256)) + ',' 
		+ (Math.floor(Math.random() * 256)) + ')';  
 
	// Use the color-animation plugin to animate the change of color  
	e.animate(+
		{ 
			backgroundColor: color 
		}, 
		{
			// duration for the change
			duration: 6000, 
			// When the animation is complete, the changeColor-function is called again 		
			complete: function(){
				changeColor(e);
			},
			// This makes sure the animation is not "enqueued", so it won't block 
			// other animations on this element
			queue: false
		}
	);   
}

Note the “queue: false”-part: It makes sure that this animation won’t line up in the normal effect-queue, because it would block all other effects on this element otherwise.

I have seen this effect first here, but the code had a big flaw causing the queue to get filled within seconds which crashed some browsers.

5. Putting everything together

You now can add all code from step 3 to jQuery’s ready-event. Since I hate typing too much, I prefer the short form:

$(function() { /* Code here */ });

You should also add the first call of the changeColor-function:

// Initiate the changing colors
changeColor($('#icon'));

6. The result

You can see the final result here in a minimal version or here with more eye-candy. You can also get everything in a tiny zip-file.

Have fun!

Leave a Reply