The Wizardry of CSS Animations (And Why It's Easier Than You Think)

yoniweisbrod

Yoni Weisbrod

Posted on March 29, 2020

The Wizardry of CSS Animations (And Why It's Easier Than You Think)

For many developers (even front-end devs), animations are a bit of a mystery.

But you don't need to be a CSS ninja or professional CodePen artist to create an impressive visual effect. Most animations and effects that you see in the wild really only take a small set of skills to create.

In fact, you can learn these skills in the 6 minutes that it takes to read this article! (OK plus a few more to do the exercises.)

By the end, you'll have no problem telling a transform from a transition, or figuring out what the heck keyframes are. You'll be able to confidently put together your own animations and effects.

Like this sort-of-Mario coin animation: (give it a click)

Animation Basics

In CSS, any property that has values that fall along a spectrum can be animated.

Font sizes, colours (since they fall along a colour spectrum), onscreen position, even border radius - all these have values that can be expressed in a range. This is in contrast to properties like display, which has a closed list of potential values.

What's midway between display: block and display: none? Now there's a noggin scratcher!

So we can animate any property with a spectrum of values - and that includes the transform property.

What are CSS Transforms?

Transforms are not just for animations - they're a CSS property used to manipulate how things are rendered onscreen in general.

You can use them to execute visual manipulations, such as increasing the size of an object, rotating it, skewing it, or moving it (or scale, rotate, skew, translate). You can also specify that you want the transform to only apply on a particular axis.

Take two examples: transform: scale(0.5, 2) is a shorthand for reducing the width (X axis) of an object by half, and doubling its height (Y axis). The same syntax can be used for translating the position an object: transform: translate(5px, 50px) would move it 5px to the right, and 50px down.

Now, say this drawing is me working to get the handstand for a good year with little-to-no success. With CSS, I could get it right away if you would be kind enough to rotate me Xdeg or Xturn:

Solution:
transform: rotate(90deg) or rotate(0.5turn)

What if you wanted to deliver my handstand while making me a little taller? You can combine multiple transforms by adding them to the same line. E.g. transform: rotate(0.5turn) scaleY(2).

3D Transforms

Transforms can also operate in 3D. To create the Mario-style coin animation, you'll need to rotate the coin on its Y axis. 2D rotations don't help much for a circle in this case (think turning a coin around as it lies flat), so you'll need to use rotate3d and tell the browser which axis you want it to move along:

Syntax: transform: rotate3d(x, y, z, degrees) where (x,y,z) are each a number between 0 and 1 denoting the axis. To rotate an item exactly along the X axis by 90 degrees, you would use: rotate3d(1, 0, 0, 90).

What happens when you try to rotate this coin by 45 degrees along the Y axis? What if you do a regular 2D rotation? What about a 90 degree 3D rotation?

Solution:transform: rotate3d(0, 1, 0, 45deg) Interestingly, the coin disappears when we rotate it 90 degrees. This makes sense in real life - imagine rotating a real coin 90 degrees. If it has no depth, it would disappear from view. In CSS, items can never have depth (or "extrusion"). We could create 3d space by using the perspective property on a parent box and then translate the Z position toward or away from the viewer (transform: translateZ(Xpx)), but this wouldn't create depth - it would just move the object closer or further away.

Transitions: Getting from Property A to B

Now, what if you wanted to animate the movement of an item from point A to B? Or a color change, or a rotatational transition, or a scale transition, or one of the many other CSS properties that are animatable? (See the full list here). This is where we arrive at transitions.

To define a basic (non-keyframe) transition, you need to tell the browser the styling at a starting moment in time, the styling once the transition is complete, and any other information about the transition itself. For example:

Example 1 - A hover effect

Let's create a simple sunshine effect when the mouse hovers over the sunshine.

Syntax: To create a transition, you can either use the shorthand to define all properties in one line:

transition: border-radius 2s ease-in 5s;

Or you can define each property individually, e.g.:

transition-property: border-radius;
transition-duration: 2s;
transition-timing-function: ease-in;
transition-delay: 5s;

This is our starting sunshine - hover over it, and you'll see the halo. But sunshine doesn't look like that!

Let's create a nice gradual sunshine effect by adding a transition for the box-shadow property on the sunshine.

Solution: transform: box-shadow 2s; and clever observers will note that I used the same actor as I did for the coin above ;)

Example 2 - The coin spin

Let's go back to our previous coin, but now I want you to add a spin rotation. The user clicks this coin, and then it spins on its Y axis 180 degrees. To do this, you'll need to declare a rotational transform on the active state and a transition on the base state. You can practice on the initial coin here.

And check your work or look at the desired effect here: (click and hold)

Notice that the animation goes backwards when the active state is removed. That's because the transform changes to an implied rotation of 0 once the object is no longer active. The same transition is re-applied, but back towards the starting value.

Example 3- Doubling up

Let's combine two transitions! To animate this Mario-style coin effect, you can combine two transitions on a single line, e.g.:

transition: transform 2s, padding 100s

To make the coin value magically appear while rising upwards, define a transition on the opacity and top values. (click and hold the coin to see the starting effect)

Solution:transition: opacity 2s, top 2s; Now what if you wanted the money value to slowly rise up, appear, and then quickly re-dis-appear upwards into the sky, like smoke?

You'd need finer control over the animation, which you'd get with..

Animation + keyframes

The css animation property replaces transitions when we want finer-grained control over our animations - either by describing component parts of the effect with keyframes, or by setting other values of the animation. In contrast with regular transitions where the start and finish CSS are defined on the object, with animations, only the starting CSS is defined on it. After that, the animation property takes over until the end.

Animation shares many attributes with transition, and - like transitions - you can define its values in shorthand or as individual properties.

One thing you must supply, however, is the corresponding keyframe:

.myObject {
    animation: fancy-keyframes 5s linear;
}

You can define the keyframe by declaring a keyframes @at-rule, and then using from, to, percentages of the entire sequence, or any variation of the above. For instance:

@keyframes fancy-keyframes {
  from {
    top: 0;
    opacity: 0;
  }
  10% {
    top: 10px;
    opacity: 1;
  }
  75% {
    top: 0px;
    margin-top:
  }
  to {
    top: 200px;
    opacity: 0;
  }
}

At this point you should have all the skills necessary to build the final rising-smoke animation! Challenge yourself to build this by going back to the previous CodePen and implementing it with keyframes!

This is the effect that we're going for. No peeking at the CSS just yet! (click and hold to see the effect)

Industry secret: One tricky thing here is to pause an animation at a single point. To do that, you can just duplicate a keyframe at a later percentage :)

But of course, this isn't actually how coin grabbing works! We shouldn't have to hold our mouse down to get the animation to play until the end. There are some (really) hacky CSS ways to accomplish this, but honestly - this is the point where I would hang up my CSS hat and put on my Javascript hat. Right tools for the right job.

We can accomplish this with React, Vue, or any framework, but all we need to do is add a class onClick, so we might as well just use vanilla JS (remember that?).

We'll create a Javascript function that adds a class (element.classList.add(myClassName)), and then add it to the onClick of our coin element. Aaand while we're at it, we'll add some more animations to our animations!

And now, without further ado... click the coin:

Happy animating!


If you enjoyed this post, have a look at a few lessons that I've created at egghead.io.

Credits

Many thanks to Nitzan and Deb for taking the time to go through this post and give me terrific feedback! And to Ofer and Diana for inspiring me to write this post after coming up with some impressive visual effects at Lemonade Insurance.

💖 💪 🙅 🚩
yoniweisbrod
Yoni Weisbrod

Posted on March 29, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related