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
.
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.
1..Octocat {2. height: 300px;3. width: 800px;4. background: url(./octocat.png) left center;5.}
But we only want to show one frame at a time, so change the width to size of one frame.
1..Octocat {2. height: 300px;3. width: 200px;4. background: url(./octocat.png) left center;5.}
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 leftleft and reach position 400px
on the sprite image.
1..Octocat {2. height: 300px;3. width: 200px;4. background: url(./octocat.png) left center;5. background-position: -400px 0px;6.}
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.
1..Octocat {2. height: 300px;3. width: 200px;4. background: url(./octocat.png) left center;5. animation: upAndDown 5s ease infinite;6. }7. @keyframes upAndDown {8. 0% {9. background-position: 0px;10. }11. 50% {12. background-position: -200px;13. }14. 100% {15. background-position: 0px;16. }17.}
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.
1..Octocat {2. height: 300px;3. width: 200px;4. background: url(./octocat.png) left center;5. animation: upAndDown 2s steps(1) infinite;6. }7. @keyframes upAndDown {8. 0% {9. background-position: 0px;10. }11. 50% {12. background-position: -200px;13. }14. 100% {15. background-position: 0px;16. }17.}
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,
1.transform: translate(0px, 100px);
and then animate up pass the midpoint,
1.transform: translate(0px, -100px);
and finally animate back down to the starting position:
1.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%
.
1.@keyframes swim {2. 0% {3. transform: translate(0, 100px);4. }5. 40% {6. transform: translate(0, -100px);7. }8. 100% {9. transform: translate(0, 100px);10. }11.}
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.
1.@keyframes upAndDown {2. 0% {3. background-position: 0;4. }5. 1% {6. background-position: -200px;7. }8. 41% {9. background-position: 0;10. }11. 100% {12. background-position: 0;13. }14.}
Finally, we can update the element with both animations by comma separating them.
1.#octocat {2. height: 300px;3. width: 200px;4. background: url("./octocat1.png") left center;5. animation: upAndDown 5s steps(1) infinite, swim 5s ease infinite;6.}
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.