If you ever built or used a mobile webapp, you must certainly have seen a CSS3 transform in action, whether you knew it or not. Today most webapps use a navigation system that slides from one page to the other: that's done using transforms. Sometimes, they also use components that emulates the native scrolling behaviour in order to keep fix elements in the page (like a header, a footer or both) and that's done using transforms. Now if you want to animate an element of your page, you should also be using CSS Transforms
CSS Transforms Vs JS animations
Prior to CSS3, animations in a web page where done using JavaScript. The downside of this approach was that it could stress your poor browser... so you didn't even want to think of that in your mobile browser. Today, CSS Transform can do the same thing as what we used to do using JS except that it requires far less efforts from your browser!
I won't explain here the term "hardware accelerated" that you may have heard here and there, but it's mostly what makes CSS transforms so powerfull. Not all transforms are hardware accelerated, mostly those who are in the 3d space. That's why, in Wink, we use 3d transforms as much as possible... This technique is sometimes also used as a trick to accelerate the rendering of certain elements: for instance applying a 3d translation of 0px on each axis to a canvas will speed up the rendering (especially noticeable on Android).
So, in a mobile browser: always use CSS Transforms when they are supported (which, at the time of this article, means at least in iOS, Android, Blackberry 6+, Bada, WebOS and on Opera mobile and Firefox Mobile). Now what should you do when they are not supported, for instance if you're building a webapp that should run on IE mobile on Windows Phone 7 ? Should you still try to emulate their behaviour with JavaScript ? In my opinion, I would say don't ! Lots of risks to end up with a bad User eXperience for very little benefits... but once again, that's just my opinion.
Different kinds of transforms
Now that we've seen the benefits of using transforms over JS animations, you should know that there are various possible transforms: translate, rotate, scale, skew and matrix. Most of the time, you will use the 3 first transforms. I won't detail all of them since their name speaks for themselves :) but I will give you a bit more details on the "matrix transform".
Since in linear algebra, linear transformations can be represented by matrices, then each combination of a translation, rotation, scale and skew can also be represented in the form of a matrix. If you're in 2D, in the end, you will get a 3*3 matrix. If you are in 3D, thus adding a perspective projection, you will endup with a 4*4 matrix. You could calculate the result yourself, based on the proper transformation matrix but fortunately, in Webkit, we have the WebkitCSSMatrix object that will be doing all this work for us.
If you use Wink for your animations and you start mixing the various transforms: we use the matrix notation.
Examples of transforms set in WebKit (as you will see, whether you are in a 2d or 3d space, the notation is quite different):
// Translation of 100px on the X-axis and 100px on the Y-Axis
wink.byId('node').style['-webkit-transform'] = 'translate(100, 100)';
// Translation of 100px on the X-axis, 100px on the Y-Axis and 50px on the Z-Axis
wink.byId('node').style['-webkit-transform'] = 'translate3d(100, 100, 50)';
// Transform in a 2D space (Translation of 100px on the X-axis and 100px on the Y-Axis) -> 3*3 matrix
wink.byId('node').style['-webkit-transform'] = 'matrix(1.000000, 0.000000, 0.000000, 1.000000, 100.000000, 100.000000)';
// Transform in a 3D space (Translation of 100px on the X-axis, 100px on the Y-Axis and 50px on the Z-Axis) -> 4*4 matrix
wink.byId('node').style['-webkit-transform'] = 'matrix3d(1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 100.000000, 100.000000, 50.000000, 1.000000)';
CSS Transforms Vs CSS default styles animation
What is possible also now with CSS3 is to animate some of the CSS properties of a node: its opacity, margins, height, width, left and right properties... There are times when these are very useful, for instance if you want to create a fadeIn/fadeOut effect by playing on the opacity. Now you may wonder why using a CSS Transform like "translate" when you could just apply a transition to the left property of your element, which would visually have the same effect.
Well, once again, that's mostly a matter of hardware acceleration: transitions on the default styles are not accelerated and thus slower than 3d transforms. A very good example of that is the way you build an accordion: you could animate the height of each accordion's panel for rendering the expand/reduce, or you could use "translate3d" on the Y-axis. Try this with a large number of panels in your accordion and with large contents in each panel and you will feel the difference ;) Once again, as with JS animation, always prefer transforms !!
CSS Transforms & Transitions
Great, we've introduced CSS Transforms but they wouldn't be that great without transitions... very simply, transitions are what we use to say: "I want this object to go from state 1 to state B in X milliseconds". Otherwise, your object would simply go from A to B instantly. Transitions comes with different options: you can specify of course the duration of the transition. You can specify a delay for your transition (the transition will start only after Y milliseconds for instance) and you can specify a timing function for your transition (do you want your transition to go more smoothly at the begining, or at the end...). Now let's see how Wnik can help you with all that.
Wink & CSS Transforms
Wink has a great set of libraries that could help you with your CSS transforms. As I mentionned above, it will automatically pick the best adapted transform for you (3d when possible, 2d otherwise), depending on the device on which your webapp is running ; and adapt it to the browser you're using (the transform property is still a prefixed one, so whether you are on gecko, webkit, presto... the syntax will be different). The same for transitions... let's say you want to translate a node (called "myNode") from 150px to the left in 1.5 second, in a linear way, starting as soon as the action will be triggered.
First step: let's specify the transition.
In the "fx" package (included within the core), Wink has an "applyTransformTransition" method. I guess the name is self explanatory :) The first parameter is the node you want to animate. The second is the transition duration. The third is the transition delay and the lat one the timing function. I didn't described the various types of timing functions, but the most used are certainly : "linear", "ease-in", "ease-out" and "ease-in-out" (once again, self explanatory).
wink.fx.applyTransformTransition(wink.byId('myNode'), '1500ms', '0ms', 'linear');
Second step: let's apply the transform.
Remember, we want to move our node to the left from 150px. Wink.fx has 3 methods: translate, rotate, scale. We will be using the first one
wink.fx.translate(wink.byId('myNode'), 150, 0);
And that's it...
Knowing when a transition ends
A very interesting event is the "transitionend" event which will tell you when a transition on a node ended. It is very usefull because sometimes you will want to do something at that time: for instance with the sliding panels in Wink, when the slide ends, we sometimes hide some elements and we can do this thanks to the "transitionend" event. Once again, Wink help you deal with it. Let's say you want to listen to the "transitionend" event on "myNode" previously used, then it would go like this:
wink.fx.onTransitionEnd(wink.byId('myNode'), function()
{
alert('transition just ended')
}, true );
If set to "true", the last parameter indicates that we want to listen to the "transitionend" event at all times and not just once.
Dealing with more complex animations
That was a great first step but you may now want to use more complex animations within your webapp. For instance if you want to first translate and then rotate your node. In this case, Wink has a library called "animation" which is an extension to the fx package but which is not included into Wink core. So if you want to use it, you'll have to pay attention to your scripts inclusions ;) We there decompose animations into parts and each part is ordered. The process goes in 3 steps:
- Init the composed transform
- Set the different parts
- Launch the animation
That's how to do it:
// Init the composed transform
wink.fx.initComposedTransform(wink.byId('myNode'));
// Set the different parts
wink.fx.setTransformPart(wink.byId('myNode'), 1, { type: 'translate', x: 0, y: 100, z: 0});
wink.fx.setTransformPart(wink.byId('myNode'), 2, { type: 'rotate', x: 0, y: 0, z: 1, angle: 50});
// Launch the animation
wink.fx.applyComposedTransform(wink.byId('myNode'));
This technique can also be used for simple animations (in this case, the animation would probably just have one part). We use this technique in most of our 3d and advanced graphical components
Conclusion
Now you should know more about CSS Transforms and Transitions, and how to deal with them in Wink. It's time for you to have fun and see for yourself how powerfull CSS Transforms are ;)
Note that I didn't speak at all about the 3d perspective thing or the origin of transforms here because this is a rather specific topic...