How to Animate a Bouncing SVG Icon With CSS

Today you’ll learn how to use CSS animations to make an arrow SVG icon bounce up and down. You’ll also learn how to tweak the animation type, timing, and duration with some of the many CSS animation properties.

An arrow pointing down that bounces up and down
Get the code on CodePen.

Why is this useful?

Animations, when done right, can:

  • Guide your users
  • Encourage your users to take action
  • Grab your users attention (while you still have it).


You’ll need a text editor to follow along. If you don’t have your own local development environment, I recommend CodePen since. You can get started coding immediately.

Alright, let’s get started!

HTML: adding the container & arrow

To recreate the demo example, you need four HTML elements:

  • An image element for the arrow icon
  • A span element for the text label above the arrow
  • A container-footer element to wrap around the arrow & text label
  • A container element to wrap around all elements

Go to your HTML editor and add the following markup inside your <body></body> element:

<div class="container">
  <div class="container-footer">
    <span class="text-label">Explore</span>
      class="arrow-circle-down bounce"
      viewbox="0 0 1792 1792"
        d="M1412 897q0-27-18-45l-91-91q-18-18-45-18t-45 18l-189 189v-502q0-26-19-45t-45-19h-128q-26 0-45 19t-19 45v502l-189-189q-19-19-45-19t-45 19l-91 91q-18 18-18 45t18 45l362 362 91 91q18 18 45 18t45-18l91-91 362-362q18-18 18-45zm252-1q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"

The arrow code we added above is in SVG format. It’s based on the Font Awesome CSS icon library.

You can pick between hundreds of Font Awesome icons in SVG format from this GitHub repo.

Save your resources!

A lot of websites load the entire Font Awesome library on their website, but they only use a small handful of icons — that’s a waste of bandwidth. You can save a lot of resources by downloading the 5-10 icons that you actually need in SVG format.

For this example, we’re embedding the SVG file directly in the HTML markup. This approach is called inline SVG. There are many other ways to add SVGs for different purposes — but I’ll save that for a different tutorial.

I use this SVG icon in this tutorial.

If you compare the original SVG source to the one you see in the HTML markup above, you can see that I made a few changes:

  • I removed the width and height properties (the original file is way too big)
  • Added a class: arrow-circle-down which we’ll need in the CSS section.

Ok next up let’s add a bit of styling, and then we’ll get on to the fun part, with CSS animations!

Styling the container and arrow with CSS

Inside your CSS stylesheet, add the following rule-sets (classes, properties, and values):

* {
  margin: 0;
  padding: 0;

.container {
  display: flex;
  background-color: #26a1ff;
  height: 100vh;

.container-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: auto auto 1rem auto;

.text-label {
  text-transform: uppercase;
  font-family: helvetica;
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  color: #fff;

.arrow-circle-down {
  display: block;
  width: 40px;
  height: 40px;
  margin: 16px 0;

Now if you refresh your browser window, it should look like this:

An arrow at the bottom of the container, pointing down

What’s happening in the CSS:

  • First, we give the parent div element’s .container class a height value of 100vh. This makes it take up the entire viewport, no matter the device. We use the display: flex; property to make it a flex container, which we’ll need for the arrow & text label. We also give it a nice light blue background color.
  • Then we give the .arrow-circle-down class a fixed width and a height of 40px so it doesn’t take up too much space. It should be noticeable, but not distracting.
  • The .text-label gets a bit of cosmetic styling with the uppercase property and some letter-spacing. Feel free to change this to your own preference.
  • We give the .container-footer a margin auto property to the top, right, and left. This forces the container footer and its children (icon & text) to the bottom of the parent container, which is where we want it. The bottom margin gets a 1rem; value to make sure everything stays within the viewport when the arrow bounces.
  • The .container-footer class also gets a few flex properties, flex-direction: column; and align-items: center;. These properties make the text and icon elements stack on top of each other and align them exactly in the center of the container footer.

For clarification, the margin: auto auto 1rem auto declaration is a nice shorthand for the more verbose:

margin-top: auto;
margin-right: auto;
margin-bottom: 1rem;
margin-left: auto;

Next up, it’s time to make your arrow bounce with CSS animations!

Animating the scroll down arrow with CSS

There are many ways to animate, both with CSS, JavaScript, and a combination. For this example, we’re going to animate purely in CSS.

We already added a .bounce class to the image element containing the SVG arrow. So far it doesn’t do anything because we haven’t defined or styled the class in CSS yet.

Add the following to your CSS stylesheet:

.bounce {
  animation: bounce 2s;

@keyframes bounce {
  100% {
    transform: translateY(0);
  40% {
    transform: translateY(-20px);
  60% {
    transform: translateY(-12px);

And now, you have a bouncing arrow:

An arrow pointing down that bounces up and down

What’s happening in the CSS code

On the SVG element with our arrow, we have a class called .bounce. This class has a property called animation.

The animation property has two values, bounce and 2s.

The bounce value is a function that triggers the @keyframe animation @keyframes bounce which I’ll get to in a moment.

The 2s value (two seconds) is the total amount of time that our @keyframe animation should run.

The @keyframe animation:

  • Has a total duration of two seconds (set by the animation property.)
  • Has a total of seven different keyframes. 0%, 25%, 40% 50%, 60% 75%, and 100%.
  • Has three different Y coordinate positions: Y(0), Y(-20px) and Y(-12px). These coordinates are what dictate whether the arrow element moves up or down at different points (keyframes) in time.

The first @keyframe block {..} says that at exactly these five keyframes: 0%, 25%, 50%, 75%, and 100%, — the arrow should be at the start position, which is Y(0px).

100% {
  transform: translateY(0);

The second @keyframe block says that at the 40% mark, the arrow should move up, by giving it a position of Y(-20px).

40% {
  transform: translateY(-20px);

The third keyframe block says that at the 60% mark, the arrow should move up again. This time we only move the arrow up around half as much as the first time, by giving it a position of Y(-12px).

60% {
  transform: translateY(-12px);

Notice that in-between the two keyframes where the arrow moves up (40% and 60%) it moves back to Y(0) at the 50% keyframe. That’s what makes the arrow to move up and down twice, relatively fast within a short period.

I decided to only move the arrow by -12px on the third position because it mimics a real-life bouncing ball. The second down a ball hit the ground it will move up way less than the first time. How much a ball bounces (and how high) is of course determined by multiple factors, like weight, speed, material type etc. but that only gives us more wiggle room, since there isn’t one way to do it.

If the CSS for the animation is confusing, try messing around with the duration and CSS transform translate property. With a bit of practice, it’ll be much easier to connect the dots.

  • Try to give the 40% keyframe a transform translate property of -48px and see what happens.
  • Try to give the CSS animation property a duration of 5 seconds instead of 2. Then try to give it a value of 100ms (you can use milliseconds instead of seconds).

It’s often easier to drive a concept home if you experiment with the extremes. That’s usually where I have my “aha” moments.


CSS animations have countless possibilities. Let’s briefly check out a few variations we can make to our existing animation.

The animation-delay property

Right now your arrow bounces as soon as your webpage has been loaded. You might want to delay it a bit, so your users aren’t distracted within seconds of entering your site.

You can do that by adding the animation delay property to your .bounce class, like this:

.bounce {
  animation: bounce 2s;
  animation-delay: 5s;

Now your two-second keyframe animation won’t start running until exactly five seconds after your page has been loaded.

The animation iteration count property

Sometimes you want to repeat an animation a couple of times. To repeat animations we use the animation-iteration-count property, like this:

.bounce {
  animation: bounce 2s;
  animation-delay: 5s;
  animation-iteration-count: 2;

Now your arrow starts bouncing after five seconds, but this time it repeats the keyframe animation one more time.

The infinite CSS animation

Sometimes, in rare cases, you want a CSS animation to run infinitely. To do that you change the animation iteration count to infinite; like this:

.bounce {
  animation: bounce 2s;
  animation-iteration-count: infinite;

But tread carefully with infinite animations. Nobody likes animations that spin around forever.

An exception would be if you have some type of living space background with a bunch of tiny stars with subtle blinking animations. You might want to loop/repeat an animation for that type of purpose, to keep the atmosphere dynamic.


To make this code work in all modern browsers, you should use autoprefixer. I didn’t add them in the code here because I wanted to keep the code shorter and easier to read. If you go to this CodePen you can get all the code, including the prefixed properties.

CSS Animation Resources

Has this been helpful to you?

You can support my work by sharing this article with others, or perhaps buy me a cup of coffee 😊


Share & Discuss on