CSS Transform

July 17, 2012

I saw this one site last week which had an animated Ipad that would transform on mouseover. I played with it and was quite impressed on how nice it looked, I did a mental note about it and closed the tab. Today I thought I’d try to replicate the animation, but I couldn’t, and still can’t find the original site that contained the ipad. But I replicated as much as I could out of memory.

This uses the CSS3 features transition and transform, which won’t work in Internet Explorer. I’ve added prefixes for webkit and firefox.

TL;DR = //benjaminhorn.io/data/csstransform/

The basic principle of the animation is that when you hover and move the mouse above the object it should move opposite from the mouse on the z-axis. In other words, if the mouse is on the top left corner, the right bottom corner should look like it is closer to the user than the top left corner (If that makes any sense?).

The first thing I did was to figure out what kind of CSS transform parameter I needed, the ones I settled on were perspective in combination with rotateX and rotateY.
The second thing I needed to do was to change the x and y plane on the object that we want to be animated (or in my case, I’ve changed the XY-plane on the parent object), instead of having the zero-position of x and y in the upper left corner I needed them to be in the center of the object relative to the mouse position (which in turn is relative to the object). (See below)

And here’s some maths to accomplish it.

//
// clientX and clientY is the position of the mouse relative
// to the document, which we get from the mousemove event.
var mx = e.clientX;
var my = e.clientY;

// Here we retrieve the offset position for the parentobject
// relative to the document.
// (the object that we have binded the mousemove listener to)
var bx = getbyid('parentbox').offsetLeft;
var by = getbyid('parentbox').offsetTop;

// And this is how we calculate it.
//
// The mouseposition relative to the object
// rpos = ( Mouseposition - Objectposition )
//
// And then we remove half of the width of the object
// from our relative mouse position
// newplanepos = rpos - (width/2);
//
var x = (mx-bx)-(getbyid('parentbox').clientWidth/2);
var y = (my-by)-(getbyid('parentbox').clientHeight/2);
//

So why do we need to move the x and y position? This is so the mouse position, when it’s in the upper left corner will be fully negative, and when it’s in the bottom right corner, it will be a positive number. I.e. if the objects width and height is 300px, the upper left corner would be x:-150px, y:-150px, the center position would be x:0, y:0 and the bottom right corner would be x:150, y:150. With this plane it will be easier to ‘convert’ the x and y positions to ‘rotational-degrees’.
In order to convert these we need to do some more calculations to the x and y values:

//
// We calculate the rotational degree with this formula
//
// x = position
// hw = half width
// md = Max degree
//
// degree = (x / hw) * md;
//
// For the ones paying attention, yes, we're calculating
// the percentual length from the center and then applying
// it to the maximum amount of degree we want.

x =  Math.round((x/(getbyid('parentbox').clientWidth/2))*12);
y =  Math.round((y/(getbyid('parentbox').clientHeight/2))*12);
//

Why have I chosen 12°? because with a larger number, the 2d image will look like a paper, while 12° won’t really show the edges of the device. (In the finished demo, I’ve added some box-shadow just to give the impression of sides).
The last thing we need to do is to invert our “y-plane” and create our css style:

//
// Remember a double negative becomes positive
// while a negative positive number becomes a negative
y = -y;

// Add the CSS style to the object
getbyid('innerbox').style.webkitTransform = 'perspective(800px) rotateY('+x+'deg) rotateX('+y+'deg)';

You’re done! I’ve then added some extra effects and tweaks to make it look better, but that’s the basic idea for my implementation of a fake 3d object.

The preview!

The sourcecode!

Tags