Animate an Octocat Sprite Swimming with CSS

January 30, 2020

Animating DOM and SVG elements with CSS using the @keyframes rule and animation property is usually pretty straightforward. Elements generally animate smoothly from a starting value to an ending value and all the values in between. While this works great for DOM and SVG elements, sprite images animate by displaying different images quickly in succession rather than slowly transitioning from one value to another. This article will demonstrate one technique to animate sprites with CSS by animating an Octocat sprite swimming in the ocean. Checkout the Codepen below to see the completed project.

Using Sprites with CSS

Sprite images are a collection of smaller images within a single image. To show any particular image within the collection of images, you need to specify the position and size of that particular image. For example, to show Octocat going to the right (the third image) in the following sprite image we need to specify the width of the image as 200px, the height as 300px, and the position on the image as x: 400 and y: 0.

Octocat Sprite Positions

In CSS, we can achieve this by setting the image as a background image on an element. If we set the height and width to size of the whole sprite image then we’ll see all the frames.

.Octocat {
  height: 300px;
  width: 800px;
  background: url(./octocat.png) left center;
}

Octocat Sprite full

But we only want to show one frame at a time, so change the width to size of one frame.

.Octocat {
  height: 300px;
  width: 200px;
  background: url(./octocat.png) left center;
}

Octocat Sprite Single

This shows the first frame because the position of the sprite image is at x: 0 and y: 0. If we want to show the third frame we can change the sprite image position using the CSS property background-position. The position of the third frame is x: 400px on the sprite image, but a positive value for background-position pushes an image to right which means the position on the image will be -400px. Flipping the value around to -400px will push the image to the left and reach position 400px on the sprite image.

.Octocat {
  height: 300px;
  width: 200px;
  background: url(./octocat.png) left center;
  background-position: -400px 0px;
}

Octocat Sprite Right

Animating One Step Sprites with CSS

Animating sprites in CSS, at its core, is simply changing the background-position to the appropriate frame within the sprite image at the appropriate time. The problem is that normal CSS animation animates the transition from one value to another rather than immediately switching to a new value. For example, say we want to animate Octocat from frame one to frame two with a normal ease or linear animation.

.Octocat {
  height: 300px;
  width: 200px;
  background: url(./octocat.png) left center;
  animation: upAndDown 5s ease infinite;
}
@keyframes upAndDown {
  0% {
    background-position: 0px;
  }
  50% {
    background-position: -200px;
  }
  100% {
    background-position: 0px;
  }
}

Octocat Ease

To animate sprites we need to use the steps() animation-timing-function instead. Essentially we need to jump from one frame to another and that’s exactly what the steps function does in CSS. The value passed into steps() represents how many steps the animation should show on the way to the provided value. For example, if we animate from 0 to 100 and pass 2 to steps , then the animation will show the element at 50 and 100. Sprite animations with more frames require more steps, in our case we only have two frames, for showing up and down movement, so we only need one step to transition between the two frames.

.Octocat {
  height: 300px;
  width: 200px;
  background: url(./octocat.png) left center;
  animation: upAndDown 2s steps(1) infinite;
}
@keyframes upAndDown {
  0% {
    background-position: 0px;
  }
  50% {
    background-position: -200px;
  }
  100% {
    background-position: 0px;
  }
}

Octocat Up and Down

Moving Sprites Around the Page with CSS

The steps() function is great for animating sprites but if we want to move the image around the screen smoothly then we need to use another timing function like ease or linear. We will need to define another @keyframes rule and add a second animation to the element to use different timing function.

First, we want to animate the sprite up and down using a transform. The sprite will start below the middle position,

transform: translate(0px, 100px);

and then animate up pass the midpoint,

transform: translate(0px, -100px);

and finally animate back down to the starting position:

transform: translate(0px, 100px);

To give the illusion of sinking slowly we animate quickly up, from 0% to 40%, and animate slower downwards, from 40% to 100%.

@keyframes swim {
  0% {
    transform: translate(0, 100px);
  }
  40% {
    transform: translate(0, -100px);
  }
  100% {
    transform: translate(0, 100px);
  }
}

We also need to update the sprite transtion animation. At the start, Octocat is at the very bottom of the animation which means he needs to be the first frame. But the swim animation above will immediately start animating him straight up to -100px, which means we need to immediately switch the frame to the up frame, frame 2. To do this we set the background-position to -200px at 1%.

When Octocat is at the very top of the animation, which is at 40%, we need to switch his frame back to the original frame. Again we want to do this after he’s reached the end of the movement so we reset his frame at 41%, instead of 40%. Next, we need to make sure he stays at his first frame all the way back down to the original position by setting 100% to the same position.

@keyframes upAndDown {
  0% {
    background-position: 0;
  }
  1% {
    background-position: -200px;
  }
  41% {
    background-position: 0;
  }
  100% {
    background-position: 0;
  }
}

Finally, we can update the element with both animations by comma separating them.

#octocat {
  height: 300px;
  width: 200px;
  background: url("./octocat1.png") left center;
  animation: upAndDown 5s steps(1) infinite, swim 5s ease infinite;
}

Octocat swimming up and down

Extending this pattern further we can create more complicated animations like the one in the Codepen at the top of the article or even tie these sprites to keyboard input.

Conclusion

Animating sprite images in CSS, while not exceedingly difficult, requires a few tricks to get working correctly. If you’d like to play around with sprites in CSS you can download the Octocat sprite my friend made below or search online for thousands of free sprite images.

Octocat Sprite Image