In today's post, we'll be taking a look at how you can use CSS3 transitions to power your application's animations with jQuery's .animate() method as a fallback where transitions aren't supported. The benefit of transitions is that unlike JavaScript based animations, they're hardware accelerated in certain browsers and mobile devices, resulting in a potentially smoother overall animation than you would normally experience.
In a lot of cases your code will work seamlessly with the solutions presented today, so the effort involved in applying them is minimal. Before we get started, if you'd prefer to see a sample of demos using today's fallbacks before reading the post, feel free to check some out below.
Demo Gallery
Superman sample animation scene View demo
Interactive demos


Basic bouncing-ball concept View demo
Introduction to CSS3 Transitions
For readers who haven't looked into transitions before, we're going to go through a quick overview of exactly what CSS3 transitions have to offer. Transitions are a part of the draft CSS3 specification and provide a means to animate changes in CSS properties rather than having those changes take effect instantaneously.
With transitions, the computed value of a property transitions over time from the old value to the new value. What this means is if a script queries the computed style of a property as it is transitioning, it will see an intermediate value that represents the current animated value of the property.
Let's take a look at an example of transitions in action: if we wanted to change CSS properties such as the margin, padding and height of an element on hover, normally this would happen instantaneously. With transitions however, the change can occur over an interval of time using a number of short-hand easing equations. Sample code for how to achieve this with CSS3 transitions for a miniature gallery can be found below:
.note {
padding:30px;
color:#000;
font-family: Arial, Helvetica, sans-serif;
text-align:center;
width:100px;
height:150px;
margin:10px;
float:left;
text-shadow:0px 1px 1px #fff;
background: #83C8F7;
background: -moz-linear-gradient(top, #83C8F7 0%, #207ce5 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#83C8F7), color-stop(100%,#207ce5));
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#83C8F7', endColorstr='#207ce5',GradientType=0 );
box-shadow:0px 7px 14px #666666;
border-top:1px solid #fff;
}
.photo{
border:1px solid #fff;
width:95px;
height:120px;
margin-top:10px;
background:url('http://addyosmani.com/blog/wp-content/uploads/2011/04/painting21.gif');
background-position:-100px -120px;
}
.photo:hover{
padding:5px;
height:150px;
margin:-25px 0px 0px -5px;
box-shadow:1px 4px 2px 0px #000;
background-position: -450px -120px;
/* apply transitions to all properties*/
-moz-transition: all 0.5s ease-out;
-o-transition: all 0.5s ease-out;
-webkit-transition: all 0.5s ease-out;
transition: all 0.5s ease-out;
}

Demo: http://jsfiddle.net/addyosmani/WApWn/show/
For a complete list of CSS properties that are animatable see the W3C specs on transitions here: http://dev.w3.org/csswg/css3-transitions/. I also recommend reading http://samuli.hakoniemi.net/css3-transitions-are-we-there-yet/ for a look at a wide range of different CSS3 transition demonstrations.
CSS Transition support
Below we can see a list of the browsers that have been confirmed as supporting CSS3 transitions.
- Google Chrome 9+
- Opera 10.5+
- Firefox 4+
- Safari 3.2+
Although this list is promising, one of the main issues with implementing CSS3 transitions now is that support for them is not what could be described as fully cross-browser compatible. As they're a relatively recent feature, users who are still on older browsers (IE6+, Firefox 3 and below) won't be able to view them as animations and this can be challenging if you're aiming for a consistent user-experience. There are however solutions to this problem and we'll be taking a look at some of them in today's post.
Cross-browser Transitions with jQuery
If CSS3 transitions aren't going to be available, the next obvious language to fall back on is JavaScript. Using Modernizr, a popular feature detection tool, we can detect support for CSS3 transitions quite easily. We are then able to serve up JavaScript powered animations to browsers which don't support it.
Next, rather than handling all of the cross-browser challenges of smooth animation ourselves, we can make use of jQuery's .animate() features to provide the same animation effect if it can't be done in the current browser using CSS3. The only problem that then remains is getting .animate() to use CSS3 transitions if they're supported and easily fallback to jQuery if they're not. So what do we need to make this happen?
Our requirements:
- Detect the vendor prefix needed for the current browser's version of transitions
- (if they're supported) fallback to jQuery
- if they're not attempt to support as much of the documented jQuery .animate() signature as possible (with respect to callbacks, duration, properties etc) within the scope of the post.
Note: Keep in mind that .animate() is considerably more complex than what I'll be showing you in the following example – this will support most basic animations, but really serves as a starting point for the solutions I'll be recommending later.
JavaScript: jquery.css3transitions.js
$(function(){
/*Note: you can replace getPrefix() with Modernizr._vendorPrefix in production. I'm showing an alternative implementation here just so that you can
see what's effectively being done under the hood*/
function getPrefix( prop ){
var prefixes = ['Moz','Webkit','Khtml','0','ms'],
elem = document.createElement('div'),
upper = prop.charAt(0).toUpperCase() + prop.slice(1),
pref = "";
for(var len = prefixes.length; len--;){
if((prefixes[len] + upper) in elem.style){
pref = (prefixes[len]);
}
}
if(prop in elem.style){
pref = (prop);
}
return '-' + pref.toLowerCase() + '-';
}
$.fn.extend({
defaultAnimate: $.fn.animate,
animate: function(props, speed, easing, callback) {
var options = speed && typeof speed === "object" ? jQuery.extend({}, speed) :{
complete: callback || !callback && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
easing: callback && easing || easing && !jQuery.isFunction(easing) && easing
};
return $(this).each(function() {
var $this = $(this),
altTransition,
easing = (options.easing) ? easing : 'ease-in-out',
prefix = (getPrefix('transition'));
if (Modernizr.csstransitions)
{
$this.css(prefix + 'transition', 'all ' + speed / 1000 + 's ease-in-out').css(props);
setTimeout(function() {
$this.css(prefix + 'transition', altTransition);
if ($.isFunction(options.complete)) {
options.complete();
}
}, speed);
}
else{
$this.defaultAnimate(props, options);
}
})
}
});
});
JavaScript: app.js
$(function(){
function updateStatus(msg){
$('.status').html(msg);
}
function compatTest(){
if (Modernizr.csstransitions) {
$('.compat span').html('yes');
}
}
compatTest();
$('.alt0').animate({width: '480px'}, 4000, function(){
updateStatus('Animation 1 Complete');
});
$('.alt1').animate({width: '480px'}, 5000, function(){
updateStatus('Animation 2 Complete');
});
$('.alt2').animate({width: '480px'}, 7000, function(){
updateStatus('Animation 3 Complete');
});
});
HTML:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Demo 1</title>
<link href='css/style.css' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Dancing+Script' rel='stylesheet' type='text/css'>
<script type='text/javascript' src='js/jquery-1.5.1.min.js'></script>
<script type='text/javascript' src="js/modernizr-1.7.min.js"></script>
<script type='text/javascript' src="js/jquery.css3transitions.js"></script>
<script type='text/javascript' src="js/app.js"></script>
</head>
<body>
<div class="container">
<h1>CSS3 Transitions</h1>
<h4>with a jQuery fallback</h4>
<div class="bar"><div class="box alt0"></div></div>
<div class="bar"><div class="box alt1"></div></div>
<div class="bar"><div class="box alt2"></div></div>
<div class="notebar compat">CSS3 transitions supported? <span>no</span></div>
<div class="notebar">Using : sample code</div>
<div class="notebar status">Waiting for animations to complete...</div>
</div>
</body>
</html>
Demo Preview:

Demo:
http://jsfiddle.net/addyosmani/A89Sq/show
While this works fine for animating basic properties using the signature variants supported by .animate(), the routine above is in no way comprehensive for complete coverage of what it's fully capable of. If you're looking for something good enough for production use, I recommend reading on below for an introduction to two more complete implementations of transition fallbacks.
If you did however want to play around with the above could further, there are a number of areas in which it could be improved. It could include support for fx steps, fadeIn()/fadeOut(), CSS3 transitionend events, jQuery's queues and delay() as well as improve the interpretation of more complex CSS3 transitions and transforms.You could also easily add support for the shorthand animation speeds 'slow' and 'fast' through jQuery.fx.speeds.slow and jQuery.fx.speeds.fast if needed.
Additional Demos:
Adrian Sinclair, a fellow developer interested in transition fallbacks came up with this next demo which we'll be also testing out later with two other fallback solutions we'll be reviewing. Adrian's demo below uses a slightly different version of code than I presented above but it's aiming at the same general idea of transition fallback support through jQuery.

http://jsfiddle.net/addyosmani/Mxyaj/show/
More Robust Solutions
Rather than investing time and effort into extending the above code, I'd like to recommend two other solutions that are both more feature extensive, but also which get updated more regularly than the example I've shown you today.
jquery.transitions.js
The first solution I'd like to recommend is jQuery plugin developer Louis-Rémi Babé's jquery.transition.js. It's a robust jQuery fallback for CSS3 transitions and here's what Louis had to say about it when I spoke to him earlier:
"Unlike other transition polyfills, this plugin is not a monkey patch over jQuery animation mechanism. It is actually a patched version of effects.js (animation component), stripped from the redundant code to make it a lightweight plugin.
The main benefit is that the full jQuery API is available. Even better, it has been designed to be compatible with cssHooks. The first compatible one is jquery.transform.js. Others will follow.
jquery.transition.js has been tested against jQuery unit-tests, and only 8 of them fail, mostly for timing issues. It benefits from the experience of writing csstransition.net to workaround implementation quirks.
In my opinion, its a good practice to test animations both with and without the plugin to see if the benefit experienced is real"
To summarize, let's now breakdown the benefits and downsides to using jquery.transitions.js:
Benefits
- It supports the complete jQuery API, failing only 8 tests in the official jQuery test-suite
- Due to test coverage, you're ensured a significantly more stable solution that will work with more complex animations
- In addition to animate() it also supports show(), hide(), fadeTo(), toggle() and stop()
- Supports jQuery queues.
- Compatibility with jquery.transform.js
Downsides
- Limited Opera compatibility – transitions in jquery.transitions.js work best with Mozilla and Webkit based browsers. The source claims the reason for this is the instability of Opera 11's transitions implementation. This is easily patchable however if you still want to enable CSS3 transitions rather than the fallback for Opera.
- Transitions are disabled for special easing and step functions.
The minor downsides aside, in my experience Louis's solution is considerably more stable for heavy-duty animations than many of the other homebaked solutions out there. I definitely recommend checking it out.
jQuery transitions demos:


Demo 1 (Progress Bars): http://jsfiddle.net/addyosmani/XKrcX/show
Demo 2 (Box Grid): http://jsfiddle.net/addyosmani/fQhsv/show
Demo 3 (Sliding content): http://jsfiddle.net/addyosmani/55qRn/show/
Bonus demo:
As we've been taking a look at fairly simplistic animations so far, it's also useful to compare how well the transitions plugin handles actual animated scenes.
For this purpose, I've created a sample scene from 'All-Star Superman' which will similarly use CSS3 transitions if they're supported, but happily run using jQuery's standard .animate() if not. It's a short scene as this is just a demonstration, but you can easily see some of the benefits of maintaining the jQuery-stynax you're already used to for defining animations vs. perhaps opting for writing out all your transition statements separately.
var animScenes = animScenes || {};
animScenes = {
city: $('#container'),
superman : $('#superman'),
dc : $('#dccomics'),
lex : $('#lexluthor'),
logo : $('#supermanlogo'),
triggerScene1: function(){
var sq = this;
this.dc.animate({'opacity':'0'},3000, function(){
sq.triggerScene2();
});
},
triggerScene2 :function(){
var sc = this;
this.dc.remove();
//animate city for fake perspective
this.city.animate({'top':'-200px'}, 5000);
//superman flies into view
this.superman.show().animate({'width':'436px','height':'326px'}, 3000);
//lex flies close to catch up
this.lex.show().animate({'marginTop':'90px', 'width':'190px','height':'190px'}, 5000, function(){
//superman speeds away
sc.superman.animate({'marginTop':'-400px','marginLeft':'1000px'}, 500, function(){
//lex chases after
sc.lex.animate({'marginTop':'-320px','marginLeft':'1000px'}, 300);
//end scene with logo fading in
sc.logo.show().animate({'width':'500px','height':'228px'}, 900);
});
});
}
};
animScenes.triggerScene1();
If you're looking for an .animate() solution that provides stable, tested CSS3 transition support, I strongly recommend using Louis's plugin. You can get the sources to it over on GitHub.
jQuery.animate-enhanced.js
The other solution you might like to check out is Ben Barnett's jQuery.animate-enhanced.js. Similar to Louis's, his plugin analyzes the properties you're animating on and selects the most appropriate approach for use in your current browser.
Benefits
- Supports fadeIn(), .fadeOut(), .slideUp(), .slideDown() and slideToggle().
- Supports $.fn.stop([clearQueue, jumpToEnd, leaveTransforms])
- Includes $.translate() method to calculate x/y transforms from CSS3 Matrix
- Animation 'queue' support (including .delay())
- Supports Opera out of the box
Downsides
- Works well with simple animations but can run into issues with more complex ones
- Occasionally has issues with animation and positioning
I first played around with Ben's plugin about five months ago and I think the only downside to it is that it occasionally has trouble animating more complex animations which is something I haven't seen jquery.transitions.js affected by as much. It's still quite a strong contender for usage and I'd recommend reading up on it more before making a decision on which plugin is right for you.
Ben's plugin is almost identical to the jQuery animate() function, but unlike Louis's comes with three additional parameters, which are optional:
- avoidTransforms: (bool) By default his plugin converts left and top animations to the CSS3 style -webkit-transform (or equivalent) to aid hardware acceleration. This functionality can be disabled by setting this to true.
- useTranslate3d: (bool) By default the plugin uses 2d translations due to wider browser support. Setting this to true to use translate3d instead. This is recommended for iPhone/iPad development.
- leaveTransforms: (bool) By default if the plugin is animating a left or a top property, the translate (2d or 3d depending on setting above) CSS3 transformation will be used. To preserve other layout dependencies, once the transition is complete, these transitions are removed and converted back to the real left and top values. You can set this to true to skip this functionality.
jQuery Animate-Enhanced demos:


Demo 1 (Progress Bars): http://jsfiddle.net/addyosmani/XSLbe/show
Demo 2 (Box Grid): http://jsfiddle.net/addyosmani/kfGUc/show
Demo 3 (Sliding content): http://jsfiddle.net/addyosmani/XwJHe/show/ (breaks the layout whilst jquery.transitions.js doesn't)
Conditional Polyfill Loading Approach
Another approach to handling the requirement for a fallback is by using a conditional polyfil loader like yepnope (if you're interested in a tutorial on yepnope, I wrote one for .net magazine back in issue #213) . With the help of Modernizr, you could easily test for CSS3 transition support in the script loader phase and then load a pure CSS3 version of the animation using a stylesheet if transition support is detected. If not, you could then load a jQuery + fallback script version of the animation.
yepnope({
test: Modernizr.csstransitions,
yep: 'animation.css',
nope: ['base.css', 'jquery.transition.js', 'animation.js'],
complete: function () {
alert('Everything has completed loading!');
}
});
The reason I personally prefer not doing this is because it requires you writing two versions of the same animation (one in CSS, another in JS/jQuery) whilst simply defining your animation through jQuery's .animate() (and having a plugin convert to transitions for you) can be easier depending on the complexity of what you're working with. Use your best judgement with respect to how you structure your solution, but you should now have at least a general idea of at least two ways this problem could be tackled. The above works best if your animation code is not likely to be complex.
Conclusions & Important Notes





This is very very good XD
Demo 3 is not working in latest stable Opera – no color columns visible!
I've released a few upgrades recently to support more easing algorithms and a few other fixes.
Please add any issues (particularly those positional ones – great test by the way) on Github and I'll get to them as soon as.
Nice Post Addy
very inspiring, i like the first demo…i'll give it a try…thanks
Wow, what the fantastic uses of jQuery. I liked all the examples.
Thanks!
Thanks! just what I have been looking for!
You're welcome, guys!
Thanks a lot for the info and for the demos!
Really nice. I like demo 1. It's cute.
You can explain more how to install it on wordpress? use with category or tag?
If you're looking to install this on WordPress, your best bet is probably going to be adding in any of the jQ/JS logic into an external .js file that works alongside markup you publish via either a post or page. The CSS needed can easily go into any themes style.css / CSS files.
Marvelous Demo..I like the work..
Hey this is awesome, great post. I've released a few upgrades recently to support more easing algorithms and a few other fixes.
Please add any issues (particularly those positional ones – great test by the way) on Github and I'll get to them as soon as.
Thanks, Ben!. Excited to try out some of the upgrades you made
Pingback: CSS3 Animation With jQuery Fallbacks | Follia Digitale
Nice, detailed post.
I've been thinking about transitions for a while, and I can't help feeling that now the 'right' way to define them is in CSS. I can see the benefit of adding them to jQuery animate, but my gut says there is something beautiful about defining them in CSS that animate() lacks – typically less code, less logic, and the ability to easily define complex effects like animating children.
So I have a plugin that approaches the problem from the other end [cough, cough, github.com/stephband/jquery.transitions]. It adds .addTransitionClass() and .removeTransitionClass() to the jQuery.fn namespace. These fallback to .addClass() and .removeClass() when transition support is not detected, or when fallbacks are not provided in the options.
I realise that one of the points above is to avoid defining animations twice, and in this scheme the the fallback function will typically contain .animate() calls – but where I do complex transitions in CSS, I'll usually provide a simple alternative in JS, or none at all if it's not critical.
You could see this as graceful degradation rather than progressive enhancement – but it's not: any transition definition is an enhancement.
Anyway, I admire the work that's going into these plugs and will be nicking some ideas
Cheers!
[Oh, and before you flame me, when I say 'right' I don't mean to imply that anyone is 'doing it wrong'!]
Very interesting. I don't think at all that there's a 'right' or 'wrong' way to approach this problem just yet, but I will be checking out your jquery.transitions plugin. It's certainly an approach to the problem I hadn't considered.
Yes, sorry, bad choice of word. Just trying to express a gut feeling about how I like to approach the problem.
Oh! I didn't think there was anything wrong with your choice of words at all
I actually wrote up a much more detailed response to your comment initially, but intensedebate decided to swallow it up. In terms of preference to approach the problem, as I said I think that developers and designers should use whatever they feel the most comfortable with. As long as the end solution has the level of cross-browser compatibility or the experience you're happy users with specific browsers seeing, I'd say feel free to experiment!
I don't think there's par se, a 'right' or 'wrong' way to approach this problem just yet but defining your syntax in the way you feel most comfortable with is definitely something to consider. I believe I may have mentioned this in the post, but I feel that if your animations aren't overly complex, it may well make sense to go the extra distance to do a version in CSS3 and another in JS. Hopefully one day such workarounds to get it functional cross-browser will be a distant memory
One nice thing about CSS3 transitions is that you can animate a very large number of elements at once and synchronously while jQuery animations are based on single elements. This was really a problem for us when we tried to animate several hundreds of divs. As solution we build a little library called jQuery Mass Animate that animates style rules instead of element styles. So if you are facing the same problem then have a look at https://github.com/medihack/massanimate
Your solution looks quite interesting (and again, thanks to everyone posting about transition and animation-related resources, they're definitely helpful). Do you have any perf tests or numbers on how well this might compare to the standard way of animating with jQuery?
Pingback: Link-urile săptămânii 4-10 aprilie | Staicu Ionuţ-Bogdan
demo 1 does not work in IE
Pingback: Animazioni CSS3 con fallbacks in jQuery! | sastgroup.com
Pingback: Animazioni CSS3 con fallbacks in jQuery! | buonaguida.com
I am working in a Software House in Pakistan http://www.hiconintl.com. And i read this post which is very informative.
Nice Tutorial, I liked the demo 3
Great tutorial and tips. Keep up the goodwork.
this tutoria is superb. jQuery can do miracles if used correctly
A wee update on jquery.transitions (github.com/stephband/jquery.transitions) – automatic IE fallback support!
I made the discovery today that IE lets you read unsupported CSS properties of nodes, through:
// For IE6, IE7, IE8
jQuery(node).css('transition')
// For IE9
(window.getComputedStyle && getComputedStyle(node, null).transition)
This is good news. It has allowed me to write automatic animation fallbacks for CSS transitions that are defined in CSS and applied by adding and removing a class with .addTransitionClass() and .removeTransitionClass().
awesome posting.. ive been looking for this.. explain everything in there in details. thank you again. no ad words to give it a click
great….
Pingback: Useful CSS3 Tutorials From 2011 | qeqnes | Designing, jQuery, Ajax, PHP, MySQL and Templates
Your post is really good providing good information..! Keep up!
Pingback: Amazing HTML5 and CSS3 Tutorials 2011 « arena3000
This is pure awesomeness, excellent. Thank you for sharing.
i like superman .. great .
Pingback: - TechnoGrate
This is a quite excellent read for me. Have to admit that you are one on the most effective bloggers I ever saw. Thanks for posting this informative article.
Thanks!
Pingback: -webkit resources for Tablet Hybrid Apps | [the]PrintLabs
Pingback: 40 Excellent CSS3 Tutorials | 1 step web design
An excellent post and very helpful tutorial which can be a very huge help to those who doesn't know.
Note that Yepnope.js is include in Modernizr. So you just have to do :
Modernizr.load({
test:
….
});
Will CSS3 transitions can do an animation like of the flash? Such a great code I might try this on the project Im currently working on. Thanks
Depending on the type of animation you’re attempting, some ‘flash’-like effects are possible. Keep in mind cross-browser compatibility however as some of the current 3D transformations are only still possible in a limited number of browsers.
A complementary post: http://blogs.msdn.com/b/eternalcoding/archive/201…
One particular awesome thing regarding CSS3 transitionis actually that you could animate… Im developing a large project and with animation. Let me try try your codes. Thank you
Pingback: Web Design SEO Ecommerce – 2 Hour Sites» Web Design Trends in 2012
Pingback: Web Design Trends in 2012 | CS5 Design
Pingback: Web Design Trends in 2012 | Momoto Design
Pingback: Web Design Trends in 2012 | Evolve Inc
Pingback: Web Design Trends in 2012 « Cloud9 Web Designs
Pingback: WDL博客视点:2012年网页设计趋势 - 逼他网
Pingback: WDL博客视点:2012年网页设计趋势 | 资讯门
Pingback: WDL博客视点:2012年网页设计趋势 | 69UI.com | UI前端设计
Pingback: 2012年网页设计趋势 | 刘兴涛&LiuXingTao.com™
Pingback: Creabite. Mordisco Creativo. – Web Design Trends in 2012
Pingback: Trends for 2012 | Entice
Great demo. Of all the demos I have found, this is by far the most robust. JQuery fallbacks, Modernizr… you guys are on top of your stuff. Thanks.
Pingback: Wordpress Web Design Trends for 2012 - The Media Group
I don’t if someone still sees this post, but i have kind of a problem with using jquery.transitions.js.
Today i’ve tested my ass off on on my mac with all browsers, on windows with explorer, iphone, android, ipad and allthough it works everywhere it still looks like it’s not as smooth as real css transforms for some reason. when i have the same simple animations done in css.
Has anyone else have the same ‘problem’? I feel it’s like the plugin is still using the native jquery animate instead of css transitions….