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.
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 by creating a radial gradient with the hex color #59798e
.
<div class="Bender"></div>
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.
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.
<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>
.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.
<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>
.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 to create the top and bottom eyelid respectively. Using position: absolute
, set the eyelids directly above the eyes as shown in the image below.
These will be hidden, however, by the Bender__socket
element which has overflow: hidden
.
.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.
@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.
.Bender__eye::before {
animation: 5s ease-in-out 1s infinite topEyelid;
}
.Bender__eye::after {
animation: 5s ease-in-out 1s infinite bottomEyelid;
}
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.
@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);
}
}
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.
Top comments (7)
Omfg this is AMAZING.
Can you do Hypno toad next? Not like it's my favorite character or anything 😅
😍This is just too cool.
amazing 😍
11/10 !!
best CSS animation ever. PERIOD.