Learn CSS animation by creating pure CSS loaders
Tags: css, beginners, tutorial, animation
Published: 2019-11-26 14:07:42

You always wanted to learn the essentials of CSS animations? Me too! Let's do it together in 5 minutes by creating some pure CSS loading animations.

## Before we start

CSS animations are already some years old. [Browser support](https://caniuse.com/#feat=css-animation) is completely given for the current versions of all major browsers. We will cover a fallback for older browsers at the end of this tutorial.

## The syntax

Let's dive directly in by looking at the following example:

```html
<!-- HTML -->
<div class="simple-spinner"></div>
```
```css
/* CSS */
.simple-spinner {
  height: 48px;
  width: 48px;
  border: 5px solid rgba(150, 150, 150, 0.2);
  border-radius: 50%;
  border-top-color: rgb(150, 150, 150);
  animation: rotate 1s 0s infinite ease-in-out alternate;
}
@keyframes rotate {
  0%   { transform: rotate(0);      }
  100% { transform: rotate(360deg); }
}
```
<div class="highlight"><pre class="highlight"><span class="c">// RESULT</span><div><img src="https://thepracticaldev.s3.amazonaws.com/i/mt1sovsoaq92tnlk25kv.gif" /></div></pre></div>

Looks pretty cool already! What's happening here? First we build a ring by giving a `<div>` the same width and height, a border where one single side has a different color and applying a border-radius of 50%. To apply an animation, we see two things:

1. Define the `animation` property on the element we want to animate
2. Define a `@keyframes` rule

### The animation property

`animation` is a shorthand property to set multiple animation properties at once. Let's take the example above and look at them in detail:

| example | property | description |
| ------- | -------- | ----------- |
| rotate | [`animation-name`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-name) | the name of the animation to use |
| 1s | [`animation-duration`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-duration) | how long one animation cycle lasts |
| 0s | [`animation-delay`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-delay) | how long to wait for the animation to start |
| infinite | [`animation-iteration-count`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-iteration-count) | how many times the animation should be repeated |
| ease-in-out | [`animation-timing-function`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function) | how an animation progresses in one cycle |
| alternate | [`animation-direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction) | animate forwards, backwards or alternating back and forth. |

This means, we specified an animation called "rotate", one cycle (360°) lasts one second, there is no start delay, the animation itself lasts forever, animation progress is not linear and it alternates back and forth (every second cycle is backwards).

*Note: To be complete, there are also [`animation-fill-mode`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode) and [`animation-play-state`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-play-state), but we won't cover those two properties in this tutorial.*

### The @keyframes rule

Now let's come to the part, where the animation is actually created. With the help of `@keyframes`, you can specify states along the animation timeline. For each state, you can define when to appear (a percentage of the animation time) and which style declarations to apply.

Our example above animates from 0% `transform: rotate(0);` (no rotation) to 100% `transform: rotate(360deg);` (one complete rotation).

Of course the same `@keyframes` rule can be used by multiple elements. Here is an example of two elements with a different `animation` rule, using the same `@keyframes` declaration:

```html
<!-- HTML -->
<div class="double-spinner"></div>
```
```css
/* CSS */
.double-spinner {
  height: 48px;
  width: 48px;
  border: 5px solid rgba(150, 150, 150, 0.2);
  border-radius: 50%;
  border-top-color: rgb(150, 150, 150);
  animation: rotate 1s 0s infinite linear normal;
}
.double-spinner::after {
  content: '';
  height: 40%;
  width: 40%;
  display: block;
  margin: 10px auto;
  border: inherit;
  border-radius: inherit;
  border-top-color: inherit;
  animation: rotate .5s 0s infinite linear reverse;
}
@keyframes rotate {
  0%   { transform: rotate(0);      }
  100% { transform: rotate(360deg); }
}
```
<div class="highlight"><pre class="highlight"><span class="c">// RESULT</span><div><img src="https://thepracticaldev.s3.amazonaws.com/i/92mvx2lai2r612qt778u.gif" /></div></pre></div>

For the start and end states (`0%` and `100%`) you can also use the keywords `from` and `to` like this:

```css
@keyframes rotate {
  from { transform: rotate(0);      }
  to   { transform: rotate(360deg); }
}
```

Let's look at an example with some more states:

```html
<!-- HTML -->
<div class="flip-walker"></div>
```
```css
/* CSS */
.flip-walker {
  width: 64px;
  height: 64px;
}
.flip-walker::before {
  content: '';
  display: block;
  width: 50%;
  height: 50%;
  background: rgba(150, 150, 150, .5);
  animation: flip 2s 0s infinite ease normal;
}
@keyframes flip {
  0%   { transform: translate(0, 0)       rotateX(0)       rotateY(0);      }
  25%  { transform: translate(100%, 0)    rotateX(0)       rotateY(180deg); }
  50%  { transform: translate(100%, 100%) rotateX(-180deg) rotateY(180deg); }
  75%  { transform: translate(0, 100%)    rotateX(-180deg) rotateY(360deg); }
  100% { transform: translate(0, 0)       rotateX(0)       rotateY(360deg); }
}
```
<div class="highlight"><pre class="highlight"><span class="c">// RESULT</span><div><img src="https://thepracticaldev.s3.amazonaws.com/i/4bh9xlfjz4mlszrsptdm.gif" /></div></pre></div>

Here we applied some [CSS transformations](https://developer.mozilla.org/en-US/docs/Web/CSS/transform) in five different states, to animate a flipping square.

## Multiple animations

It's possible to apply multiple animations to the same element. If we want to make our flipping square from above glow at the same time, we can simply add another animation separated by comma:

```css
/* CSS */
.flip-walker::before {
  /* ... */
  animation:
    flip 2s 0s infinite ease normal,
    glow 2s 0s infinite linear normal;
}
@keyframes flip {
  /* ... */
}
@keyframes glow {
  to { background: white; box-shadow: 0 0 15px white; }
}
```
<div class="highlight"><pre class="highlight"><span class="c">// RESULT</span><div><img src="https://thepracticaldev.s3.amazonaws.com/i/wo82ca9ec9m9f3vipat1.gif" /></div></pre></div>

*Note: I only used the `to` rule and left the `from` rule out. This is possible because browsers will use the element's existing/initial styles for the missing start or end states.*

## Custom timing function

If you're not happy with the default timing functions, you have the possibility to define your own with the help of a cubic-bezier curve. There are a lot of tools to define such a curve, I'm mostly using [this one](https://matthewlein.com/tools/ceaser) by Matthew Lein.

And here comes the last example of this tutorial:

```html
<!-- HTML -->
<div class="pulse"></div>
```
```css
/* CSS */
.pulse {
  width: 64px;
  height: 64px;
  background: white;
  border-radius: 50%;
  animation: pulse 1s 0s infinite cubic-bezier(0.000, 1.010, 0.5, 1.200) normal;
}
@keyframes pulse {
  from { transform: scale(0);   opacity: 1; }
  to   { transform: scale(1.0); opacity: 0; }
}
```
<div class="highlight"><pre class="highlight"><span class="c">// RESULT</span><div><img src="https://thepracticaldev.s3.amazonaws.com/i/ect53mk78cxk5k3jmt5s.gif" /></div></pre></div>

The timing function was just replace by the `cubic-bezier(0.000, 1.010, 0.5, 1.200)` I created.


## Fallbacks

If you want to provide support especially for older browsers, you can use the [`@supports` at-rule](https://developer.mozilla.org/en-US/docs/Web/CSS/@supports) for a feature query and provide a fallback e.g. as a GIF. Here is a simplified example:

```css
/* CSS */
.animated {
  background: url(animation-as.gif);
}
@supports (animation-name: test) {
  .animated {
    background: none;
    animation-name: test;
    /* ... */
  }
  @keyframes test {
    /* ... */
  }
}
```

Browsers that don't support the `animation-name` property or even the `@supports` rule will simply show the GIF image as background of your element.

## Wrap it up

With the help of some simple CSS loading animation examples on a single element we've seen how to create CSS animations, define different animation states, use multiple animations and create custom timing functions. That's everything you need to create your own awesome CSS animations! 🔥

In case you want to play with the above examples, I put them together in [this pen](https://codepen.io/devmount/pen/YzzBOgo). If you have any questions or want to share your creation, feel free to post a comment.

---

*Published: 26th November 2019
Cover Image: https://codepen.io/devmount/full/NWWZKEN*