Cool CSS Animation

Discover just how much you can do with CSS animation by learning to code cool, abstract effects with CSS.

Showcase

CSS Animation Examples

CSS animation is powerful. When combined with the power of Sass loops, you can create really interesting animations with a few lines of code. The examples below represent a small range of what you can do with CSS animation.

By using basic CSS transforms, such as scale and rotate, with animation delays, the keyframe animations really come to life.

See the Pen Planar Shuffle by Miriam Nadler (@mknadler) on CodePen.

See the Pen Deep Rings by Miriam Nadler (@mknadler) on CodePen.

See the Pen Möbius 6hedrons (pure CSS) by Ana Tudor (@thebabydino) on CodePen.

See the Pen trickling cubes (pure CSS 3D) by Ana Tudor (@thebabydino) on CodePen.

See the Pen Shift by Nick Ciliak (@nickcil) on CodePen.

See the Pen Shuffling Squares by Nick Ciliak (@nickcil) on CodePen.

See the Pen Four Corners by Nick Ciliak (@nickcil) on CodePen.

See the Pen Hypnotized by Nick Ciliak (@nickcil) on CodePen.

Tutorial

How to code cool CSS animations

This tutorial is an introduction to coding cool CSS animations using HTML and CSS. It's meant for those who already have a good understanding of HTML and CSS, with some familiarity with Sass.

From what I've found, the most challenging part isn't understanding the code but rather learning how to experiment. That's why it is important to have real-time visual feedback when coding a CSS animation. I prefer to use a browser-based editor that refreshes automatically as I code. (I recommend CodePen!)

Using CSS keyframes, animation delays, and CSS transforms, we'll create a simple yet interesting CSS animation. Let's get started!

1

Create an HTML element to animate

Start with a single element. This will form the basis of the CSS animation. To make it easier to manage the animation as a whole, create a wrapper element and set position: absolute on the elements inside.

/* Sass */
.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  background-color: turquoise;
}

<!-- HTML -->
<div class="animation-wrapper">
  <div class="circle"></div>
</div>
2

Repeat the element to create a pattern

Duplicate the element, then use a Sass loop to space them out. Each can be targeted using the :nth-child selector. To spread the elements out, I’m setting the left property instead of transform: translate() because the transform property will be set as part of the animation later and I don't want to overwrite it.

/* Sass */
.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  background-color: turquoise;
}

@for $num from 1 through 8 {
  .circle:nth-child(#{$num}) {
    left: ($num - 1) * 30px;
  }
}

<!-- HTML -->
<div class="animation-wrapper">
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
</div>
3

Add motion using CSS keyframes

Keep it simple here. I've found the best way to start adding motion is to create keyframes and animation the transform property. In this example, I'm animating transform: translate(). For the keyframes, I start by keeping it to one or two steps and adding more in later.

/* Sass */
.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  background-color: turquoise;
  animation: move-the-circle 1s infinite;
  transform-origin: center center;
}

@for $num from 1 through 8 {
  .circle:nth-child(#{$num}) {
    left: ($num - 1) * 30px;
  }
}

@keyframes move-the-circle {
  0% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(0, 50px);
  }
  100% {
    transform: translate(0, 0);
  }
}

<!-- HTML -->
<div class="animation-wrapper">
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
</div>
4

Stagger the motion using CSS animation delay

Using the same Sass loop as before, set the animation-delay property to be slightly offset for each element. This instantly makes the CSS animation dramatically more interesting.

/* Sass */
.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  background-color: turquoise;
  animation: move-the-circle 1s infinite;
  transform-origin: center center;
}

@for $num from 1 through 8 {
  .circle:nth-child(#{$num}) {
    left: ($num - 1) * 30px;
    animation-delay: $num * .1s;
  }
}

@keyframes move-the-circle {
  0% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(0, 50px);
  }
  100% {
    transform: translate(0, 0);
  }
}

<!-- HTML -->
<div class="animation-wrapper">
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
</div>
5

Experiment with different values and properties

This is where the fun comes in! In the @keyframes block, what happens when you change the background-color, opacity, and scale() of the element? By experimenting with different values and properties, you can create many variations using the same basic setup. Try adding in more keyframe steps, adjusting the timing, and changing values until you create something cool and new.

/* Sass */
.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  background-color: turquoise;
  animation: move-the-circle 1s infinite;
  transform-origin: center center;
}

@for $num from 1 through 8 {
  .circle:nth-child(#{$num}) {
    left: ($num - 1) * 30px;
    animation-delay: $num * .1s;
  }
}

@keyframes move-the-circle {
  0% {
    transform: translate(0, 0) scale(1);
    opacity: 1;
    background-color: turquoise;
  }
  50% {
    transform: translate(0, 50px) scale(.4);
    opacity: .5;
    background-color: blue;
  }
  100% {
    transform: translate(0, 0) scale(1);
    opacity: 1;
    background-color: turquoise;
  }
}

<!-- HTML -->
<div class="animation-wrapper">
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
</div>

Try it out!

It's easy to get started creating cool CSS animations with our CSS animation generator. Try it out and see what you can create!

Cheatsheet

CSS Animation Snippets

There's no need to start from scratch when creating your CSS animation. Use the CSS animation, keyframes, easing, and Sass loop code snippets below to get started.

CSS Animation Basics

Easy Animation Shorthand

.class {
  animation: my-animation 1s ease infinite;
}

End animation on last frame

.class {
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

Keyframes Block

@keyframes my-animation {
  0% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(0, 0);
  }
}

CSS Animation Easing & Timing

Easing with keyword

.class {
  animation-timing-function: ease-in;
}

Easing with bezier function

.class {
  animation-timing-function: cubic-bezier(.44,.24,.83,.67);
}

Bounce easing

.class {
  animation-timing-function: cubic-bezier(.4,1.21,.83,1.16);
}

Sass Loops for CSS Animation

Sass Loop (Delay)

$total: 10;
$delay: .1s;

@for $n from 1 through $total {
  .element:nth-child(#{$n}) {
    animation-delay: $n * $delay;
  }
}

Random Number Function

@function randomNum($min, $max) {
  $rand: random();
  $randomNum: $min + floor($rand * (($max - $min) + 1));

  @return $randomNum;
}

Sass Loop (Keyframes)

$total: 10;
$delay: .1s;
$duration: 2s;

@for $n from 1 through $total {
  .element:nth-child(#{$n}) {
    animation: my-animation-#{$n} $duration ease-out infinite;
  }
		
  @keyframes my-animation-#{$n} {
    0% {
      transform: translate(0, 0);
    }
    50% {
      transform: translate($n * 10px, 0);
    }
    100% {
      transform: translate(0, 0);
    }
  }
}