Eye Candy via CSS3 Animation

   Customer Experience

In this post we discuss transformations, transitions, keyframes, timing functions, and animations. These five concepts are among the most important aspects of CSS3 animation, and understanding what they are and how they work together is enormously helpful when designing user experiences. In conjunction with this post we’ve included a large collection of custom examples highlighting how these concepts work – and work together. As you read we recommend experimenting with these examples to get a better sense for the peculiarities of CSS3 animation.

mmm candy

CSS animation has been around longer than you may think. With the gradual advent of CSS3, a bevy of new animation potential has exploded onto the web design scene. Most of the better known CSS3 animations are common syntax, meaning all browsers and devices are designed to read and execute identical CSS rules. However, the more cutting edge an animation feature, the more likely vendor prefixed syntax is required. In general, sites like Should I Prefix are fantastic references for the current state of prefixing. Browser vendors are constantly accepting new CSS features so the need for prefixing can disappear overnight.

Prefixes mean code bloat, particularly for cutting edge web designs. Fortunately, CSS preprocessors like SASS exist to help simplify CSS development. In this post we make use of SASS in our code samples. We love SASS and so should you!

Additionally, CSS animation requires learning a new set of vocabulary – transformations, transitions, animations, timing functions, and keyframes.

Transformations are CSS properties that manipulate visual aspects of a DOM element.

Transitions allow changes to one or more CSS properties over a specified duration, and rely on a trigger event to kick off.

Animations also allow changes to one or more CSS properties, but are capable of doing so indefinitely and do not require a triggering event.

Animations and transitions both use timing functions, a mathematical model which allows acceleration or deceleration of motion over the duration of the timeline.

Keyframes are collections of relative points correlating with a particular CSS property value, designed for use with the animation property.

Now let’s dive a little deeper into each concept, starting with transformations.


See the Pen CSS Animation Example 1 by Kelby Gassman (@Kelbster) on CodePen.0

Contrary to a common misconception, transformations are not animations. Transformations do not occur over time, they act upon the target element as soon as the browser loads the DOM. Like other CSS properties, transformations are capable of manipulating DOM elements in a variety of interesting ways. Consider these examples:

transform: rotate(180deg);  // rotate element clockwise
transform: scale(2.0);      // scale element uniformly
transform: skew(10deg);     // skew element by specified angle
transform: translate(20px); // move shape x pixels

To witness these effects in an animated state, the transformation must be coupled with a transition or an animation. However, even when used without an animated driver, transformations have an advantage over more traditional CSS positioning and manipulating properties: hardware acceleration. The effort (such as it is) of executing the transformation is offloaded to the client’s GPU, reducing the strain on the CPU and boosting overall web page performance.


See the Pen CSS Animation Example 2 by Kelby Gassman (@Kelbster) on CodePen.0

Similar to animations, transitions occur over a period of time. Unlike full animations however, transitions are bound by less flexible requirements and enjoy only a small set of configurable features. Transitions begin with a triggering event – like a button hover, click, and most any other binary type event. They progress for a period of time, and end once the duration is reached. Therefore many CSS properties are ideal candidates for transitions. In fact, multiple properties can be transitioned simultaneously.

However, we advise against transitioning all available properties simultaneously unless you have a strong reason for doing so, as this may cause a significant hit to browser or device performance.

Consider this transition:

  #myAnim1 {
    div {
      left: 0;
      &:hover {
        left: 50px;
        transition-delay: 0.5s;
        transition-duration: 1s;
        transition-property: left;
        transition-timing-function: ease;

The <div> has the left property set to 0. Ordinarily when the browser applies the :hover pseudo-class, left changes immediately to 50px. However, since transition is targeting the left property, the change delays for half a second, runs for one second, and uses the ease timing (which we will discuss below).

In the above example we use all four of the explicit transition rules, but in webkit browsers this condensed line can also be used:

-webkit-transition: left, 1s, ease, 0;

For now we recommend configuring each transition rule separately to ensure compatibility in most of the other browsers and web enabled devices.


A keyframe is a fancy term for a collection of steps incremented from 0% (or “from”), to 100% (or “to”), specifying the exact value of a CSS property at a given step. For example:

@keyframes myCube {
  0%   { transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg); }
  25%  { transform: rotateY(-90deg); }
  50%  { transform: rotateY(-180deg); }
  75%  { transform: rotateY(-270deg); }
  100% { transform: rotateY(-360deg); }

The keyframe titled “myCube” specifies a five step sequence. Percentages are used because each step is relative to the duration of the animation, therefore ensuring the keyframe is consistent when used by multiple animations with a variety of running times. By the end of this sequence an object animated using the myCube keyframe will have rotated a full 360 degrees, visiting each degree of rotation at a given percentage. In this example the object’s apparent rotational speed is a function of the animation’s duration – the longer the duration, the slower the rotational speed.

Written another way: a keyframe tells the browser what to do with a CSS property (or properties) after a certain percentage of time has passed. Properties can include a transformation, like in our example above, but they can also include any other CSS property. Keyframes allow granular control over how the property changes at a relative moment in time, while still allowing the browser to do the heavy lifting of filling in the appropriate values for the remainder of the animated sequence.

Timing Functions

Transformations enable a variety of visual changes to an object, transitions allow these changes to take place over a period of time, and keyframes enable customization of CSS properties at arbitrary steps during the animation timeline. The controlling factor is the amount of time the animation runs. Without any manipulation of the animation timeline there would be no bounce, no acceleration – and no fun. How boring!

Enter the timing function. A timing function describes how an animation or a transition will proceed over its configured duration. Timing functions allow, for example, the transition of a box across the screen to begin very slow, pick up steam, go super fast, and then slow down and gently bump against the edge of the animation stage.

Browsers recognize several timing functions in the form of predefined keyword values. Some of these values include:

ease (0.25, 0.1, 0.25, 1)
linear (0, 0, 1, 1)
ease-in (0.42, 0, 1, 1)
ease-out (0, 0, 0.58, 1)
ease-in-out (0.42, 0, 0.58, 1)

Each timing function is a smooth change over time with a variety of cool accelerations and decelerations. We encourage you to experiment and discover the individual behaviors for yourself. Using a timing function is easy; in fact you have already seen it in an earlier example:

transition-timing-function: ease;

If you want more granular control over timing functions, you have two options: cubic bezier curves and steps. Cubic bezier curves are mathematically derived curves based on four points, p0 through p3. Discussing the math of a cubic bezier (while very cool) is beyond the scope of this article. However, using a cubic bezier is simple.

transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);

Do those four values look familiar? They also appear next to the ease predefined keyword. Each predefined keyword is shorthand for a cubic-bezier curve. Creating custom curves can be unusually entertaining — we recommend visiting cubic-bezier.com to test and build your own.

While conceptually dissimilar to curves, steps are perfect for creating exact, regular intervals over a period of time. No complicated math here — just define the number of animated steps and whether the animation starts at the end, or the beginning, of the interval period.

transition-timing-function: steps(8, end);


See the Pen CSS Animation Example 3 by Kelby Gassman (@Kelbster) on CodePen.0

Full blown animations are of course the pinnacle of exciting visual experiences, and CSS3 provides ample tools to build cool experiences using familiar design patterns. However, animation also requires a bit more work to code properly.

Here is how we set up the animation for Modus Cube example 5:

#myAnim5 { 
  animation-name:            myCube;
  animation-duration:        8s;
  animation-iteration-count: infinite;
  transform-origin:          40px 40px 0;
  transform-style:           preserve-3d;
  animation-timing-function: ease-in-out;

In truth, much more code is required to create the spinning cube; however these six lines define the actual animation. Note our custom keyframe at the top, followed by the duration of the animation, the total number of iterations the animation should run, where it’s positioned to start, the behavior of child elements relative to the animated parent, and finally our preferred timing function. Also, this example uses common CSS syntax. For best results we recommend including vendor prefixed syntax.

While the two behave in a very similar way, there are actually big differences between transitions and animations. Recall that transitions require a trigger event to start, typically in the form of a pseudo-class like :hover, or the programmatic insertion of a CSS class. Animations on the other hand require no trigger — they can start as soon as the page loads. Also, animations are happy to loop forever. In the above example we ensure the Modus Cube keeps on spinning with:

animation-iteration-count: infinite;

Transitions last one iteration, and only start after another trigger event. Finally, animations get to use keyframes! They can go crazy and do what they want. On the other hand transitions go from initial state to final state. Points in between cannot be specified.

Wrap Up

Animation in CSS3 is uncommonly entertaining — and totally accessible. What we covered here is just the tip of an enormous iceberg. Linked below are some resources we used in the writing of this post. We encourage you to visit them and continue learning about the awesome potential of CSS3 animation. We also hope you found this post useful, and if so please leave a comment or question below.

Additional Resources

Thank god we have a specification!

The Art of Web

CSS Animatable Properties

All you need to know about CSS Transitions

CSS Transformations versus Transitions

CSS Transition Timing Property Cubic Bezier Equivalents

This website uses cookies

These cookies are used to collect information about how you interact with our website and allow us to remember you. We use this information in order to improve and customize your browsing experience, and for analytics and metrics about our visitors both on this website and other media. To find out more about the cookies we use, see our Privacy Policy.

Please consent to the use of cookies before continuing to browse our site.

Like What You See?

Got any questions?