The Animation Keyframe Gotcha

Craig Buckler
Share

I’m a big fan of CSS3 animations. Despite a tentative start and some concerns about whether they trespass on JavaScript’s behavioral responsibilities, CSS3 animations are widely supported, easy to use and permit slick effects that would have been impossible without Flash a few years ago.

Unfortunately, not all is rosy in the CSS3 garden and browser vendors often spray manure over your patch. Consider the following glowing element animation:

div
{
	width: 8em;
	font-weight: bold;
	text-align: center;
	padding: 0.5em 0;
	margin: 50px auto;
	color: #fff;
	background-color: #00c;
	border-radius: 3px;
	animation: glow 3s ease-in-out infinite;
}

@keyframes glow {
	50%  { box-shadow: 0 0 20px #aaf; }
}

View the demonstration page…
animation

(Note: -webkit prefixes for the animation and keyframes properties are currently required for Chrome, Safari and Opera 15+ but not shown in the code above. They have been added to the demonstration page.)

The animation works well in recent editions of Firefox, Chrome, Safari and Opera — but not IE10 or IE11.

Before you launch into a “it’s IE6 all over again” diatribe, let’s take a closer look at the W3C CSS3 Animations Working Draft document. In section 4. Keyframes you’ll find the following statement:

ISSUE 1 Need to describe what happens if a property is not present in all keyframes.

We have only defined one keyframe at 50% but have not explicitly defined properties at 0% and 100%. I suspect the Webkit/Blink and Gecko browsers are defaulting to box-shadow: 0px 0px 0px rgba(0,0,0,0);. However, IE’s Trident engine appears to default to box-shadow: none; — and it’s impossible to animate from “nothing” to “something”.

Strictly speaking, no browser is making a correct assumption because the specification is incomplete. Perhaps the Webkit/Blink and Gecko teams have made a more useful choice but that doesn’t make it correct. Yet.

That said, you would have hoped IE would start the animation if box-shadow: 0px 0px 0px rgba(0,0,0,0); were defined in the div selector. The specification states:

If a ‘0%’ or ‘from’ keyframe is not specified, then the user agent constructs a ‘0%’ keyframe using the computed values of the properties being animated. If a ‘100%’ or ‘to’ keyframe is not specified, then the user agent constructs a ‘100%’ keyframe using the computed values of the properties being animated.

To be fair, the CSS3 animation specification is evolving so it’s not surprising to find implementation differences. Fortunately, you can avoid cross-browser animation inconsistencies by following a few simple rules:

  1. Always include keyframes at 0% / from and 100% / to. Never forget the ‘%’ symbol either — unlike other properties, 0 and 0% are not equivalent.
  2. Always define every property being animated within every keyframe — 0% and 100% are especially important.
  3. Test often using a variety of browsers!

To ensure the glow animation works everywhere, we must change the keyframes definition:

@keyframes glow
{
	0%   { box-shadow: 0 0 0px rgba(0,0,0,0); }
	50%  { box-shadow: 0 0 20px #aaf; }
	100% { box-shadow: 0 0 0px rgba(0,0,0,0); }
}

There are no guarantees, but this code should continue work regardless of any updates to the applications or the CSS3 Animation specification.

Has this issue caught you out? Did you find a fix? Or did you give up and blame the browser?!