Cross-Browser Animated CSS Transforms — Even in IE.

April 5th, 2010 by zoltan · 25 Comments

Cross-Browser Animated CSS Clock Example based on an original WebKit example by Toby Pitman. Click image above to view.

In my first article about CSS3, I introduced a new script, cssSandpaper, which allows developers to sidestep the myriad of vendor specific properties and just use one property to implement properties like transform for all browsers, including IE.

After posting the article, I saw many examples of CSS3 Transform using animations. Toby Pitman’s Old School Clock is an excellent example of how one can use a Webkit’s -webkit-transform to make a small but excellent demo. I wanted to prove that it would be easy to take this example and make it work in all modern browsers, so I did. It took 15 minutes (okay, I had to change cssSandpaper to offer scripting support, but that didn’t take too long either). I then coded a few more examples to show that some really neat things can be done using a small bit of JavaScript.  Here are links to these examples:

How To Do CSS3 Animated Effects?

If this was the perfect world, all a developer would need to do is use a DOM element’s style property and manipulate the appropriate camel-case CSS property. For example, if a developer wanted to script the rotation of a node, he or she would code the following: = "rotate(25deg)";

However, this is not the perfect world — after all, I am not making millions writing this blog and the current flavours of IE in use today don’t support many of the CSS3 properties. However, using cssSandpaper, one could use the following method to do the same thing:

    cssSandpaper.setTransform(node, "rotate(25deg)");

Developers can use cssSandpaper to manipulate opacity, box-shadow, and background gradients, using cssSandpaper.setOpacity(), cssSandpaper.setBoxShadow() and cssSandpaper.setGradient() respectively. All these functions take two parameters: a DOM node, and the appropriate CSS property values as described in the cssSandpaper documentation. For example:

    cssSandpaper.setTransform(node, "rotate(25deg) scale(2, 2) skew(20deg, 20deg)");
    cssSandpaper.setOpacity(node, 0.3);
    cssSandpaper.setBoxShadow(node, "10px 10px 5px #ffcccc");
    cssSandpaper.setGradient(node, "-sand-gradient(linear, center top, center bottom, from(#0000ff), to(#ff0000));")

For more information, please read the official documentation of cssSandpaper.


  • When animating using transform‘s scale() function, make sure you avoid scaling objects too much larger than their original size. This is due to the fact that IE scales objects as if they were images, and scaling-up an object will make the result quite pixelated.
  • The -sand-gradient() function does not use Firefox’s native -moz-gradient function to produce CSS3 gradients, but a solution using Canvas which works in all Canvas enabled versions of Firefox. I will update cssSandpaper to use -moz-gradient in a future release (if anyone wants to help me get this working, please contact me via the email address at the top of this page, or by leaving a comment below).

Go to the cssSandpaper documentation to download the latest version.

Tags: CSS · CSS3 · gradients · IE Visual Filters · JavaScript · Polyfills · transform · ,

25 responses so far ↓
  • 4 Weston Ruter // Apr 12, 2010 at 2:43 pm

    Good idea prefixing your CSS properties/values with your own -sand-* instead of looking for existing vendor-prefixed ones; that way you are in control of their syntax and semantics.

  • 7 Anonymous // May 5, 2010 at 5:08 am

    really nice work! could you plz fix cssSandpaper.setGradient for colors with alpha values (ie needs #aarrggbb, all the others use rgba(rrr, ggg, bbb, aaa))

  • 8 zoltan // May 5, 2010 at 9:13 am

    @anonymous: this is a great idea and something I am currently looking into. I will be posting in the next few days a roadmap of what I plan to put into cssSandpaper with an open request to the web development community for feedback and feature requests. I am glad people are using it for their project and want to make it as painless to use as possible.

  • 9 Fandekasp // May 5, 2010 at 9:05 pm

    Great project, I’ll follow it very carefully

  • 10 zoltan // May 10, 2010 at 1:34 pm

    @anonymous: I have added rgba() support in the latest release of cssSandpaper. See my blog post about cssSandpaper with rgba() gradient and transform: translate support

  • 12 Adam Butler // Feb 12, 2011 at 1:12 pm

    Have you thought about including a set of “get” commands to retrieve values?

  • 13 zoltan // Feb 12, 2011 at 2:00 pm

    @Adam: yes, and it is definitely doable. The only caveat is that, in the case of css3 transforms, all browsers only store the matrix() version of the transform, so you wouldn’t be able to see the original transform if, for example, it was in the form of “skewX(45deg) rotate(67deg) transformX(80px)”, unless there is a way to factor a matrix() into the other transform functions, which I am not aware of at this time.

  • 14 Irreat // Mar 4, 2011 at 12:15 pm

    I just found out about this script and this is more than wonderful! Thanks a lot for sharing !

    However, I quickly tested it and a small problem showed up when using the basic zoom function (Ctrl + mousewheel) of Opera (11.01). When a text is displayed in a rotated/skewed box, the letters tend to overlap one another when zooming in (and move apart when zooming out). A good way to see it in action is by testing the skewTest example. Otherwise, zooming under IE, Chrome or FF is perfect.

    I’m not got at making subtle CSS so I may be missing something here, but I’m interested in a way to workaround the issue !

  • 15 zoltan // Mar 5, 2011 at 3:34 pm

    @Irreat: that is quite interesting. It seems to be a bug in the way Opera handles CSS3 transforms (all my script does is apply a -o-transform rule on the object, so I don’t believe that it is cssSandpaper.

    I have submitted a bug to Opera – hopefully this is fixed in the next release. At this time, I am not sure about any workarounds to this issue. It may be work looking into the CSS word-spacing property and setting it to some sort of em measurement, but I am not sure. I’ll try to test out that theory and post here again with my findings.

  • 16 Daniel // Mar 6, 2011 at 7:26 am

    Thank you so much!

    This saved me LOADS of work (I had just determined to move the entire visualization to Flash just make sure it works in IE7/IE8 when I discovered cssSandpaper)!!

    Since it’s a commercial project, I’ll be more than happy to provide some form of donation or similar? Please let me know if there’s anything of the sort I can do for you!

    Best regards from Sweden,
    Daniel Sundström

  • 17 Aneek Mukhopadhyay // Oct 13, 2011 at 2:27 am

    In one word, it is great. Thanks zoltan. I have mentioned about this great post in my blog also. Also used this type of transitions in IE in some of my projects.

  • 18 zoltan // Oct 14, 2011 at 6:25 pm

    @Aneek: thanks for the mention. Maybe sometime I will get around to doing a polyfill for transitions for IE :-)

  • 19 Fred Campbell // Jun 9, 2012 at 9:47 am

    I think IE has been holding back the web for long enough. Microsoft have had over a decade to create a decent browser and have failed miserably. The trouble is that the more web designers have to hack their code to bits to accommodate IE – the more chance they will continue producing sloppy browsers. If we all unite and stop IE support, either their browsers will die, or they will have to catch up with Firefox, Opera and Chrome. It is our behaviour that is letting them get away with this. My approach is to create great sites for great browsers – with just the basics for IE.

  • 20 Matt // Jun 27, 2012 at 4:22 pm

    Whenever I try to use the setTransform method, I get the following error:

    Cannot read property ‘transform’ of undefined

    …where undefined is referring to I’m using a div for the container and have required scripts linked. I’m using v1.2 and calling “cssSandpaper.setTransform($(‘#container’), ‘rotate(25deg)’);”.

    I’m just testing at the moment (minimal setup) and am using Chrome v16.0.912.63. Do you have any idea of what might cause this?

  • 21 zoltan // Aug 12, 2012 at 10:54 am

    @Matt: You must convert the jQuery object to a DOM object:

    cssSandpaper.setTransform($(‘#container’).get(0), 'rotate(25deg)');

  • 22 zoltan // Aug 12, 2012 at 11:09 am

    @Fred: I agree with you to a certain extent. However, I always have liked pushing the envelope on what IE can do, and clients do appreciate the extra work when it is possible. I am not saying that we should try to polyfill all of IE’s deficiencies with hacks, but it definitely doesn’t hurt to give elderly browsers a boost if possible to make their user experience better. I will be the first to celebrate when we don’t have to worry about there kind of workarounds.

  • 23 Snake2401 // Nov 1, 2012 at 5:08 pm

    Hi there,

    I’ve not tested sandpaper jet, but I was wondering if I could combine sandpaper rotation with the animate() function of jquery to animate a rotation fluently… Or can I do it also without jquery?

  • 24 zoltan // Nov 4, 2012 at 12:51 pm

    @Snake2401: You could use the step property of the animation object while animating a inconsequential CSS property. An example is on theAnimate element transform rotate Stack Overflow page — you will notice this code:

    $('#foo').animate({  borderSpacing: -90 }, {
        step: function(now,fx) {

    This doesn’t use cssSandpaper, so it works in all browsers except IE<=8. To get support for these browsers, include the cssSandpaper libraries and refactor the code like this (live example here for your “view-source” pleasure):

    $('#foo').animate({  borderSpacing: -90 }, {
        step: function(now,fx) {
          cssSandpaper.setTransform(this, 'rotate('+now+'deg)');
Give Feedback

Don't be shy! Give feedback and join the discussion.

Please Note: If you are asking for help using the information on this page or if you are reporting a bug with the code featured here, please include a URL that shows the problem you are experiencing along with the browser/version number/operating system combination where the issue manifests itself. Without this information, I may not be able to respond.

An orange star denotes a required field.