Draw and Animate Bender's Face with CSS
Tags: css, showdev, webdev, codepen
Published: 2020-01-23 22:04:48


Futurama's lively characters and simple animation can easily be recreated with CSS using basic shapes. Bender, specifically, is drawn almost completely with basic shapes. This tutorial will demonstrate how to create Bender's face with CSS and animate his eyelids to make it seem like he's squinting. Check out the completed project on Codepen.

{% codepen https://codepen.io/codypearce/pen/gQedwx %}

## Container and Color

First, let's create a container and define the background. The hex color `#a6b4c4` matches Bender's metal color pretty well, but we can give the illusion (sort of) of [shininess](https://futurama.fandom.com/wiki/Bite_my_shiny,_metal_ass!) by creating a radial gradient with the hex color `#59798e`.

![Bender Container](https://codinhood.com/static/8f90e450a4afbac78e53109fd92bb257/14e05/container.png)

```html
<div class="Bender"></div>
```

```css
body {
  overflow: hidden;
  padding: 0;
  margin: 0;
}
.Bender {
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  background: #a6b4c4;
  background-image: radial-gradient(#a6b4c4, #59798e);
}
```

## Eyes

Drawing with CSS is a lot easier when we can break images down into simple shapes that are easily created with CSS. Bender's eyes, for example, can be broken into three basic shapes: ellipses, circles, and squares.

![Bender Eye Breakdown](https://codinhood.com/static/7dd77498acf51f570695ca9b6d697542/14e05/BenderEyes2-01.png)

The outer rim is composed of the space between the `Beneder_eyes` border and the `Bender__socket` element. The eye elements, `Bender_eye`, have a larger height than the `Bender_socket` element so that we can clip the top and bottom parts of the eye to create the illusion that the eyes are nested _inside_ the socket. Add the following HTML elements and CSS to create the eyes.

![Bender Eyes](https://codinhood.com/static/8a7867db40a07ddf03f231a6eec38e66/43669/bender-eyes.png)

```html
<div class="Bender">
  <div class="Bender__eyes">
    <div class="Bender__socket">
      <div class="Bender__eye">
        <div class="Bender__pupil"></div>
      </div>
      <div class="Bender__eye">
        <div class="Bender__pupil"></div>
      </div>
    </div>
  </div>
</div>
```

```css
.Bender__eyes {
  width: 400px;
  height: 150px;
  border: 3px solid black;
  border-radius: 200px;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
}

.Bender__socket {
  width: 375px;
  height: 125px;
  border: 3px solid black;
  border-radius: 200px;
  background: black;
  display: flex;
  justify-content: center;
  overflow: hidden;
}

.Bender__eye {
  height: 145px;
  width: 145px;
  background: #fefbb8;
  border-radius: 100%;
  margin: -10px 10px 0px 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.Bender__pupil {
  width: 20px;
  height: 20px;
  background: black;
}
```

## Mouth

Bender's mouth is essentially an ellipse with two horizontal lines and few vertical lines. We can space seven, `4px` width, vertical lines across the `Bender__mouth` ellipse using flexbox and `justify-content: space-around`. The two horizontal lines are a little more difficult to place since they're not evenly spaced from the top or middle. But we can use `absolute` position and the `calc()` function to place them exactly where we want.

![Bender Eyes](https://codinhood.com/static/8eabc764b5bf6e14ff89fbbc590f0323/c4270/bender-mouth.png)

```html
<div class="Bender">
  ...
  <div class="Bender__mouth">
    <div class="Bender__tooth"></div>
    <div class="Bender__tooth"></div>
    <div class="Bender__tooth"></div>
    <div class="Bender__tooth"></div>
    <div class="Bender__tooth"></div>
    <div class="Bender__tooth"></div>
    <div class="Bender__tooth"></div>

    <div class="Bender__lip"></div>
    <div class="Bender__lip"></div>
  </div>
</div>
```

```css
.Bender__mouth {
  width: 275px;
  height: 100px;
  background: #fefbb8;
  margin-top: 80px;
  border-radius: 50px;
  border: 4px solid black;
  display: flex;
  align-items: center;
  justify-content: space-around;
  overflow: hidden;
  position: relative;
}
.Bender__tooth {
  height: 100px;
  width: 4px;
  background: black;
}
.Bender__lip {
  position: absolute;
  width: 275px;
  height: 4px;
  background: black;
  top: calc(33% - 2px);
}
.Bender__lip:last-of-type {
  top: calc(66% - 2px);
}
```

## Animate the Eyes

We can animate Bender squinting his eyes, like he's skeptical or angry, by animating eyelids up and down over his eyes. We could create separate components for his eyelids, but in this case, we will use the `::before` and `::after` [pseudo elements](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements) to create the top and bottom eyelid respectively. Using `position: absolute`, set the eyelids directly above the eyes as shown in the image below.

![Bender Eyelids](https://codinhood.com/static/c9b151a203b1560187b4601748983749/14e05/bender-eyelids.png)

These will be hidden, however, by the `Bender__socket` element which has `overflow: hidden`.

```css
.Bender__eye::before {
  content: "";
  position: absolute;
  width: 145px;
  height: 50px;
  top: -50px;
  background: black;
}
.Bender__eye::after {
  content: "";
  position: absolute;
  width: 145px;
  height: 50px;
  bottom: -50px;
  background: black;
}
```

The goal is to animate the top eyelid down and bottom eyelid up to give the illusion that the eyelids are closing over the eye. We can do this by adding a `transform` that translates the eyelids along the `Y` axis, for example `transform: translateY(-50px)`. Since we defined the top eyelid to be `-50px` above the eye, we need to start at that position, `translateY(0px)`, and animate back down to the near the pupil, `translateY(50px)`. The bottom eyelid needs to go in the opposite direction `translateY(-50px)`. Define two `@keyframes` that go from `0%` to `100%` for both the top and bottom eyelids.

```css
@keyframes topEyelid {
  0% {
    transform: translateY(0px);
  }
  100% {
    transform: translateY(50px);
  }
}
@keyframes bottomEyelid {
  0% {
    transform: translateY(0px);
  }
  100% {
    transform: translateY(-50px);
  }
}
```

Next, add the `animation` property to each eyelid with the appropriate keyframe name at the end.

```css
.Bender__eye::before {
  animation: 5s ease-in-out 1s infinite topEyelid;
}
.Bender__eye::after {
  animation: 5s ease-in-out 1s infinite bottomEyelid;
}
```

![Bender Eyelid animation](https://codinhood.com/fa944513e95cb31242de3aee56652f62/bender-eyelids-first.gif)

One problem with this animation is that it ends abruptly and resets the eyelids to their initial positions instead of animating them back. We can make this animation more natural by breaking the animation keyframes into more parts.

First, we get to the end animation more quickly by animating from `0%` to `20%`. Then we can hold that position by defining the same `transform` until `80%`. Finally, we can return to the starting position at `100%`. This means that the start of the animation `0%` and the end `100%` are at the same spot so the eyelid will animate away from the starting position and animate back to the starting position.

```css
@keyframes topEyelid {
  0% {
    transform: translateY(0);
  }
  20% {
    transform: translateY(50px);
  }
  80% {
    transform: translateY(50px);
  }
  100% {
    transform: translateY(0px);
  }
}

@keyframes bottomEyelid {
  0% {
    transform: translateY(0px);
  }
  20% {
    transform: translateY(-50px);
  }
  80% {
    transform: translateY(-50px);
  }
  100% {
    transform: translateY(0px);
  }
}
```

![Bender Gif](https://codinhood.com/3b09bb38f8ba907d30e5fda5d0a39408/bender.gif)

Now we have a much more natural animation.

## Conclusion

There are probably half a dozen different ways to create Bender with CSS, but I hope this version helps you see how easy drawing with CSS can be.