Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

A Beginner’s Introduction to CSS Animation

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

Nowadays, more and more websites are using animations, whether that be in the form of GIFs, SVGs, WebGL, background videos and so on. When used properly, animation on the web brings life and interactivity, adding an extra layer of feedback and experience for users.

In this tutorial I am going to introduce you to CSS animations; a highly performant way of doing things which is becoming more and more popular as browser support improves. Having covered the basics, we're going to build a quick example which will animate a square element into a circle:

An Introduction to @keyframes and Animation

The main component of CSS animations is @keyframes, the CSS rule where animation is created. Think of @keyframes as being stages along a timeline. Inside @keyframes, you can define these stages, each having a different style declaration.

Next, to make CSS animations work, you need to bind the @keyframes to a selector. This will gradually parse all the code inside the @keyframes declarations and change the initial style to the new style, based on the stages.

The @keyframes

Here we'll set the animation stages. Our @keyframes properties are:

  • A name of our choosing (tutsFade in this case).
  • Stages: 0%-100%; from (equal to 0%) and to (equal to 100%).
  • CSS styles: the style that you would like to apply for each stage.

For example:

@keyframes tutsFade {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

or:

@keyframes tutsFade {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

or the shorthand:

@keyframes tutsFade {
  to {
    opacity: 0;
  }
}

The code above will apply a transition to the opacity of an element, from opacity: 1 to opacity: 0. Each of the approaches above will achieve the same end result.

The Animation

The animation property is used to call @keyframes inside a CSS selector. Animation can have multiple properties:

  • animation-name: @keyframes name (remember we chose tutsFade).
  • animation-duration: the timeframe length, the total duration of the animation from start to the end.
  • animation-timing-function: sets the animation speed ( linear | ease | ease-in | ease-out | ease-in-out | cubic-bezier ).
  • animation-delay: the delay before our animation will start.
  • animation-iteration-count: how many times it will iterate through animation.
  • animation-direction: gives you the ability to change the loop direction, from start to end ,or from end to start, or both.
  • animation-fill-mode: specifies which styles will be applied to the element when our animation is finished ( none | forwards | backwards | both )

For example:

.element {
  animation-name: tutsFade;
  animation-duration: 4s;
  animation-delay: 1s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  animation-direction: alternate;
}

or shorthand:

.element {
  animation: tutsFade 4s 1s infinite linear alternate;
}

The code above will create a blinking effect, with a 1 second animation delay, a 4 second total animation duration, with alternate direction and infinite linear loop iterations.

Adding Vendor Prefixes

Whilst a working draft, we need to use browser-specific prefixes to ensure the best browser support possible. The standard prefixes apply:

  • Chrome & Safari: -webkit-
  • Firefox: -moz-
  • Opera: -o-
  • Internet Explorer: -ms-

An animation property using vendor prefixes will look like: 

.element {
    -webkit-animation: tutsFade 4s 1s infinite linear alternate;
    -moz-animation: tutsFade 4s 1s infinite linear alternate;
    -ms-animation: tutsFade 4s 1s infinite linear alternate;
    -o-animation: tutsFade 4s 1s infinite linear alternate;
    animation: tutsFade 4s 1s infinite linear alternate;
}

alongside with @keyframes:

@-webkit-keyframes tutsFade { /* your style */ }
@-moz-keyframes tutsFade { /* your style */ }
@-ms-keyframes tutsFade { /* your style */ }
@-o-keyframes tutsFade { /* your style */ }
@keyframes tutsFade { /* your style */ }

For the sake of readability during this tutorial I will continue further without using prefixes, but the final version will include them and I would like to encourage you to use them in your CSS code.

To find out more about vendor prefixes, you can check http://css3please.com/, which is a great website for vendor prefixes resources.

Multiple Animations

You can add multiple animations using a comma separator. Let’s say that we want to add an additional rotation to our tutsFade element, we'd do so by declaring extra @keyframes and then binding them to our element:

.element {
  animation: tutsFade 4s 1s infinite linear alternate,
             tutsRotate 4s 1s infinite linear alternate;
}
@keyframes tutsFade {
  to {
    opacity: 0;
  }
}
@keyframes tutsRotate {
  to {
    transform: rotate(180deg);
  }
}

Square to Circle Tutorial

Let’s jump in and create a simple shape transition; a square to circle animation using the above principles. We will have five stages in total and for each stage we will define a border-radius, a rotation and a different background color to our element. Enough talking, let’s jump into coding.

Basic Element

First, let’s create the markup, an element to animate. We're not even going to bother with class names, we're just going to use a plain div for now:

<div></div>

Then, using an element selector (div {}), add default styling to the div:

div {
  width: 200px;
  height: 200px;
  background-color: coral; 
}

Declaring the Keyframes

Now let’s prepare @keyframes, which we'll call square-to-circle, and the five stages

@keyframes square-to-circle {
  0%{}
  25%{}
  50%{}
  75%{}
  100%{}
}

We need to define some styes within these stages, so let's begin by dictating the border-radius for each corner of the square:

@-webkit-keyframes square-to-circle {
  0%  {
    border-radius:0 0 0 0;
  }
  25%  {
    border-radius:50% 0 0 0;
  }
  50%  {
    border-radius:50% 50% 0 0;
  }
  75%  {
    border-radius:50% 50% 50% 0;
  }
  100% {
    border-radius:50%;
  }
}

Additionally we can declare a different background-color for each stage.

@keyframes square-to-circle {
  0%  {
    border-radius:0 0 0 0;
    background:coral; 
  }
  25%  {
    border-radius:50% 0 0 0;
    background:darksalmon; 
  }
  50%  {
    border-radius:50% 50% 0 0;
    background:indianred;
  }
  75%  { 
    border-radius:50% 50% 50% 0;
    background:lightcoral;
  }
  100% {  
    border-radius:50%;
    background:darksalmon;
  }
}

To really hit the idea home, let's go beyond border-radius and background-color by rotating the div and adding a little visual interest.

@keyframes square-to-circle {
  0%  {
    border-radius:0 0 0 0;
    background:coral;
    transform:rotate(0deg);
  }
  25%  {
    border-radius:50% 0 0 0;
    background:darksalmon;
    transform:rotate(45deg);
  }
  50%  {
    border-radius:50% 50% 0 0;
    background:indianred;
    transform:rotate(90deg);
  }
  75%  { 
    border-radius:50% 50% 50% 0;
    background:lightcoral;
    transform:rotate(135deg);
  }
  100% {  
    border-radius:50%;
    background:darksalmon;
    transform:rotate(180deg);
  }
}

Apply the Animation

Having defined our square-to-circle animation, we need to apply it to the div:

div {
  width: 200px;
  height: 200px;
  background-color: coral;
  animation: square-to-circle 2s 1s infinite alternate;  
}

Here you see we've added a shorthand animation property, which states:

  • The animation-name is square-to-circle.
  • The animation-duration is 2s.
  • The animation-delay is 1s.
  • The animation-iteration-count is infinite, so it will carry on indefinitely.
  • And the animation-direction is alternate, so it will play from beginning to end, then back to the beginning, then again to the end, and so on. 

Use Timing-Function Awesomeness 

One last value we can add to the animation property is the animation-timing-function. This will define the speed, acceleration and deceleration of our movement. This function can be a very detailed value, which is awkward to calculate manually, but there are a lot of free websites which provide resources and live customisation for animation timing functions.

One such tool is the CSS Easing Animation Tool, so let's use that to calculate our timing function.

I would like to add an elastic effect to our square-to-circle animation, using a cubic-bezier function.

Having played around with the handles and generated some kind of bezier curve, update the animation timing-function value using the snippet provided.

div {
  width: 200px;
  height: 200px;
  background-color: coral;
  animation: square-to-circle 2s 1s infinite cubic-bezier(1,.015,.295,1.225) alternate;  
}

The final code, without using vendor prefixes ( -webkit- , -moz-, -ms-, -o- ) is as follows:

div {
  width: 200px;
  height: 200px;
  background-color: coral;
  animation: square-to-circle 2s .5s infinite cubic-bezier(1,.015,.295,1.225) alternate;
}

@keyframes square-to-circle {
  0%  {
    border-radius:0 0 0 0;
    background:coral;
    transform:rotate(0deg);
  }
  25%  {
    border-radius:50% 0 0 0;
    background:darksalmon;
    transform:rotate(45deg);
  }
  50%  {
    border-radius:50% 50% 0 0;
    background:indianred;
    transform:rotate(90deg);
  }
  75%  { 
    border-radius:50% 50% 50% 0;
    background:lightcoral;
    transform:rotate(135deg);
  }
  100% {  
    border-radius:50%;
    background:darksalmon;
    transform:rotate(180deg);
  }
}

One Last Thing

All works well in modern browsers, but Firefox has a nasty habit of rendering transforming objects poorly. Take a look at these jagged lines to see what I mean:

Luckily, there's a workaround for this. Add the following transparent outline to your div and Firefox will render things perfectly!

outline: 1px solid transparent;

Conclusion

That's it! We've used CSS Animation syntax to create a simple, repeating animation.

Browser Support

For up-to-date information on the browsers support for CSS animation, check out Can I use.. but in a nutshell, supporting browsers include: Firefox 5+, IE 10+, Chrome, Safari 4+, Opera 12+

Resources:

Advertisement