Pirates and CSS animations
Tags: css, animation, pirates
Published: 2019-03-12 03:57:51

---
title: Pirates and CSS animations
published: true
description: A quick and easy guide to CSS animations
tags: CSS, animation, pirates
---

> I wrote this post for my [newsletter](https://sid.studio/newsletter), sign up here to get emails like these every week.

Hi!

For my [course on React Hooks](https://react.games), I have to make a bunch of animations for it to be interesting.

![final result](https://sid.studio/blog/32/final.gif)

A few folks asked how do those animations work...

![tweets](https://sid.studio/blog/32/tweets.png)

You'll be surprised at how easy it is with CSS.

First, let's break down our composition:

1. We have a bird and a pirate that's hanging from the bird
2. They enter together from the right side of the screen
3. After reaching half way, the bird drops the pirate and leaves the screen from the left
4. The pirate falls to the bottom of the screen

&nbsp;

### Step #1: Characters



![characters](https://sid.studio/blog/32/characters.png)

```html
<div class="bird"></div>
<div class="pirate"></div>
```

```css
.bird {
  background-image: url('./bird.png');
}
.pirate {
  background-image: url('./pirate-hanging.png');
}
```



With some hit and trial, we can position the pirate at exactly the right spot.



![hanging](https://sid.studio/blog/32/hanging.png)

```css
.pirate {
  top: 27px;
  margin-left: 49px;
}
```



We need another image for the pirate in his falling state. Because the image is a vector image (SVG), we can modify it to get the right posture. (I used sketch, but you do this in any image editor)

![redesign](https://sid.studio/blog/32/redesign.gif)

Okay, now that we have the graphics ready, let's think about the _choreography_.

&nbsp;

### Step #2: Choreography

Before we write any code, it's useful to write down the different steps of the animation.

```js
t = 0     1     2     3     4     5         6     7     8     9
    ←---------  enter  --------⇥  ←  pause ⇥  ←----- exit ----⇥

1: 0s - 5s : bird: fly in + pirate: fly in
2: 5s - 6s : pause
3: 6s - 9s : bird: fly out + pirate: fall
```

Let's start with the bird flying in.

We want the bird to come in from outside the screen to the middle. We can attach the same animation to the pirate because he is hanging to the bird for this part.

Shout out to my friend [Andres](https://twitter.com/andresgalante) who helped me improve this article. He pointed out that animating `position` produces a repaint on every keyframe and using `translation` is way more performant. You should follow [Andres](https://twitter.com/andresgalante) on twitter, he's a CSS wizard.

![enter](https://sid.studio/blog/32/enter.gif)

```css
.bird {
  animation: bird-enter 5s ease-out;
}
.pirate {
  animation: bird-enter 5s ease-out;
}

@keyframes bird-enter {
  from {
    /* right end of the screen */
    transform: translateX(100vw);
  }
  to {
    /* half way */
    transform: translateX(50vw);
  }
}
```



Looking good!

By default, the characters will reposition snap to their default position after the animation is finished. That's because CSS animations do not affect the element before the first keyframe is played or after the last keyframe is played.

We can use the property `animation-fill-mode` to override this behavior:

```css
.bird .pirate {
  animation-fill-mode: forwards;
}
```

`forwards` will make the element stay in the same position as the final keyframe.

&nbsp;

Alright, let's talk about the exit.

An element can have multiple animations applied to it.

```css
.bird {
  /*         ↓ enter animation       ↓ exit animation   */
  animation: bird-enter 5s ease-out, bird-exit 3s ease-in;
}
```

Both of these animations will start at the same time though. That's not good, we want the second animation (exit) to start some time after the first animation finishes (enter).

This is where the [animation-delay](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-delay) property comes in. The delay for the exit animation should be the duration of the first animation + the pause we want to take between animations: `5 + 1 = 6s`.

Because we have multiple animations, we need to specify the delay for each of the animation.



![midway](https://sid.studio/blog/32/midway.gif)

```css
.bird {
  /*         ↓ enter animation       ↓ exit animation   */
  animation: bird-enter 5s ease-out, bird-exit 3s ease-in;
  animation-delay: 0s, 6s;
  /* 0s delay for the entry animation, 6s for the exit  */
}

@keyframes bird-exit {
  from {
    transform: translateX(50vw);
  }
  to {
    /* exit outside the frame */
    transform: translateX(-10vw);
  }
}
```



##### Sidenote: you can also write the above code with the animation shorthand, where the 4th argument is delay: `bird-exit 3s ease-in 6s`.

Okay, now let's talk about the pirate's exit. The timing is the same as the bird, but the animation is a little different. We want the pirate to fall down from it's original position to the bottom end of the screen.



![pirate falling](https://sid.studio/blog/32/fall-1.gif)

```css
.pirate {
  /*         ↓ enter animation       ↓ exit animation   */
  animation: bird-enter 5s ease-out, fall 3s ease-in;
  animation-delay: 0s, 6s;
  /* 0s delay for the entry animation, 6s for the exit  */
}

@keyframes fall {
  from {
    /* keep it's X position */
    transform: translateX(50vw);
  }
  to {
    /* keep X position, fall to the bottom end of the screen */
    transform: translateX(50vw) translateY(100vw);
  }
}
```



Okay that's a good start, but we also need to change the image.

We can attach a different `class` to the pirate element with javascript to have a different background image. But, we can also achieve this through css.

If we supply the new `background-image` to the element in the `from` and `to` of the animation, it will apply it for the whole duration.

To make the effect even better, let's rotate the pirate while he falls.

```css
@keyframes fall {
  from {
    /* keep it's X position */
    transform: translateX(50vw);
    background-image: url('./pirate-falling.png') rotate(0deg);
  }
  to {
    /* keep X position, fall to the bottom end of the screen */
    transform: translateX(50vw) translateY(100vw) rotate(90deg);
    background-image: url('./pirate-falling.png');
  }
}
```

This is the combined result:

![pirate falling](https://sid.studio/blog/32/fall-2.gif)

If we use the SVG version of the pirate instead of PNG, we can go really deep and animate each part of the pirate. Something like:

```css
.pirate .hand {
  animation: raise-up 2s ease-in;
}
```

We don't have to, of course. A few lines of CSS keyframes combined together gave a pretty good result too!

If you want to experiment, [here's a codepen link](https://codepen.io/siddharthkp/pen/ywoQLL?editors=1100) to this animation.

Hope that was useful on your journey

Sid

---

[![newsletter](https://sid.studio/newsletter-snapshot.png?v=4)](https://sid.studio/newsletter)