CSS Mastery: Animation @keyframes

CSS Transitions and transforms work beautifully for creating visual interactions based on single state changes. To have more control over what happens and when, you can use the CSS animation property to create easy CSS animation using @keyframes. This technique has a wide range of design application and can be used to build dazzling pre-loaders, interactive interfaces, effects or full-scale storytelling. In this tutorial you’ll learn how to apply what you know about CSS transitions to quickly master animation, and how to use @keyframes for applying various style rules to your element at different intervals.

If you missed it, check out Easy CSS Animation With Transition & Transforms to get your mind thinking about how your element should move. CSS transition and animation are almost the same, where animation can dig deeper by giving your element a defined timeline for when different style changes take effect.


CSS keyframes allow changes to run automatically and continuously, rather than just in response to mouse events the way transition does. They give us a way to change the CSS declarations on a given selector at any point during a state change or an event detected through jQuery (such as scrolling). Keyframes are paired with the animation property to set the durationtiming functiondelay and direction instead of transition. Properties such as transform, if part of an animation, are then declared within the @keyframes rule.

To start, each @keyframe rule gets a unique name:

@keyframes animation-name{ }

This name is used on the element’s style to pair it with the animation:

.element {   
   animation: animation-name; 

Inside it, you set a rule for a percentage representing the point along the animation’s timeline for the declared CSS styles to be rendered on the element:

@keyframes animation-name {   
  0% {     
    color: pink;   
  50% {     
    color: yellow;   
  100% {
    color: blue;

In this example, the element div with a class of element goes from pink to yellow to blue. You can also use from and to when going between only two points:

@keyframes animation-name {   
  from {     
    color: black;   
  to {
    color: white;

Here is an example of applying this simple rule to a background color change on the body:

body {
  animation: change-background 4s ease infinite;

animation Property

The @keyframes themselves do nothing without some instructions that define things like the duration, timing function and direction, which each work just like they do in the transition property. These animation sub-properties can be declared in one animation declaration using the following syntax:

animation: duration | timing-function | delay | iteration-count | direction | fill-mode | play-state | name;

Or set individually by appending animation- to the beginning of each sub-property:

animation-duration: 1s;
animation-timing-function: ease;
animation-delay: 2s;
animation-iteration-count: infinite;

…You get the idea.

Not all of these sub-properties are required, but they do have to be in the right order so the browser can apply the timing value to the right thing, or distinguish the animation name from other keywords, for example. Here is a quick run-down of the sub-properties you’ll use the most:

  • duration – Sets how long the animation runs from start to finish.
  • timing-function – Sets how the animation moves along the timing “track”, ie ease, ease-in, linear, etc.
  • delay – how much time (if any) to wait before kicking off the animation sequence.
  • iteration-count – how many times to play the animation, or infinite to loop it.

In addition to the property values we are already familiar with thanks to transition, animation takes a directioniteration-countplay-state and fill-mode.

Iteration Count

By default, animations go through one cycle, then end. The animation-iteration-count sub-property value may be set using either a number representing how many times the animation should run, or the infinite keyword to run it indefinitely.


The animation-direction subproperty does not define the visual direction of an animation (your style rules define position and start and end states) but rather tells the animation which order to run the keyframes. This sub-property can be set to normalreversealternate, and alternate-reverse.

  • The normal value plays an animation from beginning to end. The reverse value plays it backwards or bottom to top as the rules are written, starting at 100% and working backwards to 0%.
  • The alternate value will play an animation forwards then backwards, and alternate-reverse plays it backwards, then forwards.

Fill Mode

The animation-fill-mode sub-property decides if the animation styles should remain visible before or after the animation plays.

By default (normal), the styles defined inside the animation keyframes do not affect the element before or after the animation plays. Setting the fill-mode value is useful if you need the end-state of your animation to become the new state until something else happens, or to fix the abrupt change back to the original state (as you can see in our background change demo above). Here is a breakdown of what each value does:

  • backwards – Before the animation plays and there is a delay set, the styles of the initial keyframe (0%) are applied.
  • forwards – After the animation plays, the styles defined in the last keyframe (100%) remain active.
  • both – The animation will follow the rules for both forwards and backwards.

You’ll see how to use fill-mode on a hover effect to keep that abrupt flicker from happening below.

Play State

The play-state value can be set to paused or running. One useful way to implement play-state is to set it to paused on hover. If you look at our first example above, hover over the bar highlighting each keyframe as it plays, and it will pause.

.highlight {
  animation: move-highlight 4s linear infinite;
  animation-play-state: paused;

Note you can used animation: paused; or animation-play-state: paused;, but it is always best to declare a specific sub-property when resetting or overriding a previous value on state change.

Use Animation and @keyframes to Create Shutter Effect on Image Hover

This example demonstrates how you can create a “shutter” effect on an image gallery when the image is hovered. Unlike a simple hover effect using transition, this CSS animation uses keyframes to gradually change opacity on a pseudo-element while changing its size, and remove a CSS3 grayscale filter added to each image’s original state.

Here are the important bits of the CSS for the image wrapper and pseudo-element that will overlay it:

figure {
  position: relative; 
  overflow: hidden;
  margin: 0;
  height: 100%;
  width: 100%;
  filter: grayscale(.8);
figure::before {
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 2;
	display: block;
	content: '';
	width: 0;
	height: 0;
	background: rgba(255,255,255,.2);
	border-radius: 100%;
	transform: translate(-50%, -50%);
	opacity: 0;

Note the filter and opacity set on these elements. These declarations define their default states before the animation is triggered.

    animation: bloom ease-in-out .75s forwards;
figure:hover::before {
    animation: circle .75s;

Now we set the animation property for the event we want to trigger the animation. Using :hover is the simplest – you could also set a special class name on an event detected with jQuery.

In the first animation, we link it to the bloom keyframes, give it an ease-in-out timing function that will play out over .75 seconds and then return to the original style thanks to the animation-fill-mode setting of forwards – this ensures our effect doesn’t just blink back to the original grayscale effect. In our second animation, we link it to the circle keyframes and tell it to play out over the same .75 seconds.

@keyframes bloom {
	0% {
		filter: grayscale(.8);
	40% {
		filter: grayscale(.5);
	100% {
		filter: grayscale(0);
@keyframes circle {
	0% {
		opacity: .5;
                background: rgba(213,156,34,.2);
	40% {
		opacity: 1;
                background: rgba(213,34,160,.2);
	100% {
		width: 200%;
		height: 200%;
		opacity: 0;

In our bloom animation, we are taking the grayscale filter declared on the figure element our animation is set on from .8 to none. When the animation finishes, it stays at 0 thanks to our animation fill mode. If we didn’t set this, it would blink back to grayscale abruptly.

On our second animation circle, we take the element opacity from half to full, change the color to a yellow then pink, then expand the element larger while bringing the opacity back to 0.

This is the basis for creating a simple “pulse” or “shutter” effect. Note that the element opacity is separate from the color’s RGBA opacity!


Once you have the basics of CSS animation down, you can see how easy it is to come up with endless possibilities. Even still, many excellent code libraries and tools exist to help us implement CSS animations quickly. Here are a few of the best ones:


Previously, I showed you how to use Flexbox to create a split-screen layout, then use the animate.css library to animate the opening of the content pages and images. Animate.css provides several pre-made animations you can preview and then drop-in your project using a single class name. What’s more, it offers a great way to get started with learning how to apply and remove CSS classes from an element using jQuery. Be sure to check out that tutorial to learn how to kick off your animations on events like clicks or scroll points.

Cubic Bezier Tool

cubic-bezier.com provides a wonderful visual interface for making your own cubic bezier timing functions, and seeing the results in real time. The code snippet can be copied and pasted right into your stylsheets.

CSS Animate

The CSS Animate web tool helps you generate full keyframe and animation codeblocks for a jumpstart on coding complex timelines. If you were ever into Flash, this might look familiar. Simply click a spot on the timeline, drag your element into position, set its animation properties then repeat for each new point selected on the timeline. Play back your completed code to refine, then copy/paste.

More Resources

  • CSS Animation Rocks – A Collection of beginner tutorials to help you master keyframe animation
  • The Art of UI Animations – designer Mark Geyers online workshop on CSS animation, performance and tips
  • Species in Pieces – mind-blowing examples of CSS animation in action
  • Mars Landing – Mathew Gitchell’s implementation of @keyframes to create movement by changing margins
  • CSS Hovering Fairy – Judith Neumann’s implementation of @keyframes to make a fairy’s wings flutter while she hovers