Try Tuts+ Premium, Get Cash Back!
CSS3 Animations: the Hiccups and Bugs You’ll Want to Avoid

CSS3 Animations: the Hiccups and Bugs You’ll Want to Avoid

Tutorial Details
  • Topic: CSS3 animation

CSS3 animation is pretty darn cool. It lets us give hardware accelerated life to our previously dull websites. However, there are some major pitfalls and practices you should be aware of – let’s dig in.

The browser support for CSS3 animation is hotting up – Mozilla Firefox has joined WebKit in full support, and Internet Explorer 10 as well as Opera 12 have promised future support. This means we can start using them without fear today. However, this thriving support doesn’t come without its problems.


Not the Androids We’re Looking For

Being a Webkit born-and-bred property, you’d expect CSS animation to have full support across all Webkit browsers. Unfortunately, it’s not quite that simple. The browser built into Android devices does support animations – to some degree. The problem is, it will only support animations with a single changing property.

So let’s say we wanted to work with my animations framework, Animate.css, to make a super cool website. Most of the animations such as bounceInLeft will work great on the latest Chrome, Safari, Firefox and iOS Safari. But on an Android device, the user won’t see a single animated element. The animation runs, but the element disappears as soon as it’s finished.

This strange quirk means that the only animations we can run on Android devices are single property ones, such as fadeIn and bounce. Unfortunately, it’s unclear whether or not Android 4.0 will provide better support – hopefully it will.

The Animate.css home page shows absolutely nothing on Android devices

Until we see greater support from these Android devices, your best bet is to provide Javascript fallbacks or less complex animations. But how can you tell your site not to use your super cool animations on these devices? Using Modernizr won’t help here – it’ll detect that the browser supports animations. Luckily, we can check the user agent, and serve up an alternative stylesheet or script. In PHP, it’s as easy as this:

$ua = strtolower($_SERVER['HTTP_USER_AGENT']);
if(stripos($ua,'android') !== false) { // && stripos($ua,'mobile') !== false) {
	$css = "droid-style.css";
} else {
	$css = "style.css";
}

That snippet will load up droid-style.css on Android devices, meaning we can keep our fancy-pants animations for the browsers that can use them. Excellent!


For 2D, Press 3D

iOS devices like iPhone and iPad have great support for CSS3 animations, with full hardware acceleration – but only if it’s a 3D transform. If the animation doesn’t involve a 3D transformation, it’ll be accelerated purely by the software, which can result in laggy animations.

To get full hardware acceleration on animations, you need to activate the 3D rendering engine. That’s as easy as adding this rule to your CSS:

.container {
    -webkit-transform: translateZ(0);
}

Great! But why not apply this rule to the body? Well, for some reason, activating the 3D engine plays with the layout of the page a little bit. Fixed or absolutely positioned elements will shift slightly with this applied to the body.

As with all the things in the CSS3 world, this clever trick comes at a cost. Not a hefty one, but a cost nonetheless. Take a look at this scientific comparison:

Antialiasing screws up with the active 3d rendering engine

It takes a keen eye to see it, but activating the 3D rendering engine makes the antialiasing of text greyscale – this results in slightly sharper text, and it’s particularly noticeable on extremely small or extremely large text sizes. Like I said, it’s no biggie, but it’s still a bug. Adding -webkit-font-smoothing: antialiased; can help reduce the problem slightly on Webkit browsers.


The Problem With Transforms

Let’s imagine you need to move an element from one spot to another, without it affecting the layout of the page. translate is your best friend here – the translate property, as defined by the W3C:

…does not affect the flow of the content surrounding the transformed element. However, the value of the overflow area takes into account transformed elements.

See that? It doesn’t affect the flow of surrounding content. But it does affect the overflow of the document. This means that if you move an element way off the page (which is the case for a few animations on Animate.css), it’ll cause scrollbars.

Browsers treat this behavior a little differently amongst themselves. Safari and Chrome will create scrollbars, but then once the transformation is complete and the element’s opacity is dropped to zero, it’ll remove the scrollbars, as if the element has been removed. Firefox, on the other hand, creates persistent scrollbars that will stay until the element is removed from the document or set to display: none. The best way to work with these transforms is to use a little Javascript magic. If you know the length of your animation, you should remove the element from the DOM once it’s finished the animation. Alternatively, you could watch for when the animation is complete with some clever Javascript:

var element = document.getElementById("#box");
element.addEventListener("webkitAnimationEnd", function(){
    this.style.webkitAnimationName = "";
}, false);
document.getElementById("#button").onclick = function(){
    element.style.webkitAnimationName = "shake";
    // you'll probably want to preventDefault here.
};

This little snippet actually comes from a Stack Overflow thread. It’s a good one, so bookmark it!


Fighting the Flash

If you’re writing your own CSS animation, you might notice something strange on Safari, Chrome, and iOS devices. Just before the animation runs, the animated element in question will flash in and out of visibility just before it starts.

The reason behind this phenomenon is unclear, but the fix is pretty simple. Simply adding the -webkit-backface-visibility: hidden; rule to your CSS should help prevent the problem. Apply it to the container of the element, like so:

.container {
	-webkit-backface-visibility: hidden;
}

It boils down to another hardware acceleration problem – using this property simply kicks the acceleration into gear. You could also use things like -webkit-perspective: 1000; or other 3D properties.


Pseudo Elements and Z-index

Here’s another couple of unfortunate truths with CSS animations and transitions. You can’t use animations or transitions on pseudo elements. This fact is somewhat poorly documented on the web, but it’s an important one. Let’s say, for instance, you wanted an :after pseudo element to fade into visibility when you hover over it’s parent. Unfortunately, it’ll snap between states instead of transitioning gracefully. As far as we know, this is unusual behavior: there are bug reports filed for Chrome and Webkit – and Firefox actually supports these transitions. You can keep up with the current state of support for transitions & animations on pseudo elements over at CSS-tricks.

However, it is worth noting that if you apply transitions or animations to an element that has pseudo elements, those transitions will be carried through to the pseudo elements.

And now for another kick in the teeth. Transitions and animations reset the z-index of an object. If you have some nicely stacked objects you want to animate, they’ll have their stacking order reset. It’s an unfortunate truth and again, not one that many people talk about.


Realistic Motion

I might be getting into pretty deep water here, but you can make your animations a lot more realistic by playing with the timing functions. If you just leave the default timing functions for the animations (ease), you can end up with some pretty nice effects. However, if you’re trying to recreate a particular motion pattern in CSS, it’s important to learn the differences between the different timing functions. Let’s take the ‘hinge’ animation from Animate.css as an example.

The idea behind this animation was to have the element drop from its current position, swing from a single corner for a little while, then drop off completely – kind of like a broken sign. Here’s the catch – the animation will require a variety of timing functions to make it realistic. Think about this motion in real life; when the sign drops and starts swinging, it’ll start off slowly, then speed up, then slow back down at it’s peak. However, when it drops off completely, it should drop quite suddenly and speed up as it falls. Sounds like we need both ease-in-out and ease-in.

It’s actually pretty easy. Inside your keyframes, you can declare the different timing functions – like this:

@keyframes hinge {
	0% {
		animation-timing-function: ease-in-out;
		transform: rotate(-120deg);
		transform-origin: top left;
	}
	25% {
		animation-timing-function: ease-in-out;
		transform: rotate(70deg);
		transform-origin: top left;
	}
	50% {
		animation-timing-function: ease-in-out;
		transform: rotate(-120deg);
		transform-origin: top left;
	}
	100% {
		animation-timing-function: ease-in;
		transform: rotate(0deg) translateY(200%);
	}
}

By using a variety of timing functions, rather than just the default one, we have greater control over how the animation plays. If you run the hinge animation without the custom timing functions, you can see how strange it appears. when writing your animations, compare them to real life instances of the same motion. Slow it down in your mind, and think about how each one is timed.


Don’t Design Like it’s 1999

This might be the most important thing you take away, so listen up. I firmly believe that CSS animations are there to be used sparingly for added interaction, and nothing more. Clever folks like Anthony Calzadilla are making some crazy cool stuff with CSS animations, but in my opinion, in the real world these animations should be few and far apart.

Take this page as an example. Everything here (except the obligatory animated gif) is animated using CSS. It’s an extreme example, but you can see why I’m worried about the overuse of these things.

Wow. CSS3 gone bad.

The same goes for all the CSS3 properties. Transitions, shadows, and gradients should be used with subtlety. I think the landing page for Owlr makes a pretty good example. Submitting an invalid email or an empty form will create a validation error with a couple of non-essential animations to draw attention.

Nicely done.

In his book CSS3 For Web Designers, (which is a great read) Dan Cederholm talks a lot about the “experience layer”. He stresses the point that all the CSS3 values demonstrated in his book are for an added layer of experience only – the effects added are non essential, and should always degrade gracefully in browsers that don’t fully support them. Remember this rule, and you’ll become more powerful than you could possibly imagine. Or something like that.


Performance Issues

Most computers have more than enough power to run CSS3 animations and transitions with no problem – however, the more you try to pump into your CSS, the more it will affect performance.

Take for example a simple animation which moves a div from left to right infinitely. Simple stuff. Let’s make this box a little more interesting – give it a box shadow, text shadow, maybe a gradient… all these rules will affect performance of the page. If you gave your div a box shadow with a ridiculous blur radius (I’m talking into the hundreds here), you’ll notice a severe drop in performance. The browser is working so hard trying to figure out how it should render the pixels making up the box shadow that it starts hogging resources needed by the animation, or even the rest of the page – simple tasks such as scrolling can become painfully slow. Keep visual enhancements to a minimum, particularly shadows.

Hardware acceleration helps prevent this problem, but it’s still an issue to be aware of. Not all your users will have the luxury of hardware acceleration, and software rendered graphics can take their toll on the computer.


Conclusion

Hopefully you’re more aware of some of the pitfalls in CSS3 animation and all its cross browser quirks than you were before. But don’t forget that these CSS3 features are still very exciting and available to use today. Support is ever-growing, and it signals a world where we can move away from Javascript for visual effects – which is a great thing if you ask me.

I’ll finish with this simple reminder:

Your content and functionality takes priority over everything else. If you find yourself using any CSS3 features, be sure that your site will function the same way for every user without them as well.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Pingback: CSS3 Animations: the Hiccups and Bugs You’ll Want to Avoid | Shadowtek | Hosting and Design Solutions

  • http://www.rockitweb.co.uk Rockit Web

    Good writeup Dan, I’ve seen some crazy things made with CSS3.

    http://www.ecsspert.com/mcdonalds.php – Not animations but impressive all the same :)

  • http://www.egydes.com husien adel

    great article, i didn’t expect that great effects with css3 :D

  • http://antjanus.com Antonin Januska

    I was reading through the article and saw “animate.css” and I thought to myself “Sweet, I should tweet Dan about it” but when I saw the Owlr reference, I realized it was you haha. :)
    sweet article.

  • http://martealdesigns.com bob marteal

    Thanks for the ‘gotcha’ list. These can be just as valuable as ‘neat-o’ lists of new features.

  • BrianC

    For the Android support issue, wont the CSS property @media work here instead of that .PHP script ?

    • http://daneden.me Dan Eden
      Author

      If you’re referring to detecting screen width via media queries, then no – that’s not enough. CSS3 animations work wonderfully on iOS devices, using media queries would cast those perfectly capable devices aside as quickly as Android devices, as well as any browser windows below said width.

      Additionally, where would you draw that line? Under 500px in width? Because then the problem still exists for the Android tablet devices.

      The PHP snippet is probably the most robust and reliable way of targeting only Android devices.

      • BrianC

        I see – well, thanks for taking the time to clarify it for me :)

  • Pingback: » Анимация css3

  • http://davgothic.com David Hancock

    @Antonin Januska I was thinking the same thing!

    Sweet article Dan! Hope to see more!

    • http://www.snaptin.com Ian Yates

      +1

      Dan – we want to see more of you!

  • http://joshuanhibbert.com Josh

    Great article Dan! I was pleasantly surprised when I saw you were the author!

  • http://www.topz10s.com Amrinder Singh

    Great article. I love the work you did in css3.

  • Yee Yan

    Animate.css is hot. Thanks for the share with that one.

  • Pingback: Tweet-Parade (no.47 Nov 2011) | gonzoblog.nl

  • Pingback: Our favorite tweets of the week Nov 21-Nov 27, 2011 | Webdesigner Depot

  • Pingback: Our favorite tweets of the week Nov 21-Nov 27, 2011 | linuxin.ro

  • Pingback: Some links for light reading (29/11/11) | Max Design

  • Daniel Tome

    Is there any way to detect low FPS and disable shadows and other effects? I’ve got this page that has lots of elements and scrolls. It allows you to interact with drag and drop. On a Mac it works wonderfully and on a powerful windows PC too. As soon as you use a mid-level PC scrolling and dragging becomes very jerky.

    Nice article. Thanks

    • http://daneden.me Dan Eden
      Author

      Unfortunately there’s no way (as far as I’m aware) to detect hardware support, FPS etc. Theat.me goes about this probably in a pretty good way, allowing the user to enable and disable effects such as reflections and shadows to increase performance.

  • http://martinodf.com MartinodF

    Nice article!
    I can confirm all of the Animate.css demo animations work on the Android 4.0 browser.

  • http://wowizowi.com Roby LaPorte

    I would like to add text.css to a FaceBook app that is giving me a window to add html. How do a add this very simple css to this page? Any help will be greatly appreciated!

    .text {
    font-family: Arial, Helvetica, sans-serif;
    font-size: 14px;
    color: #5F3316;
    }
    </style

  • Pingback: CSS3 Animations: the Hiccups and Bugs You’ll Want to Avoid | Webdesigntuts+ » Web Design

  • http://ivorpadilla.net Ivor

    I always wondered why it flashed. Nice workaround Dan, thanks for writing this up.

  • Pingback: CSS3 Animations: the Hiccups and Bugs You’ll Want to Avoid | Webdesigntuts+ | Graynoise Media

  • http://www.facebook.com/Oniking Ckris Phoenix

    About that flashing thing. It also happens to some hover sub menus. I use “display:none”, and it becomes ok.

  • Georg

    “Fighting the Flash”: You made my day, thanks a lot!