CSS Download Loading Animation (@keyframes, clip-path)
Tags: tutorial, webdev, css, ui
Published: 2021-01-15 15:01:43

Today let's work with CSS animations & clip-path to create a nice little download animation with an indefinite and a definite mode.

Read the full article or watch me code this on Youtube:

{% youtube DpXj8xsTyAo %}

# Result

{% codepen https://codepen.io/crayon-code/pen/gOwZpRO %} 

## Markup

The markup of this loader is quite simple as it consists of one `div.downloader` for each loading animation and either the additional `.indefinite` class or the `.definite` class with a variable set to the percentage the loader should display.

```pug
.downloader.indefinite
  .arrow
  .bar
    
.downloader.definite(style="--percentage: 60%;")
  .arrow
  .bar
```

## Variable Setup

The size of the loader is controller through the `--size` CSS custom property - give it any value you want. The height of the bar and the space between the arrow and the bar is specified in percent whereas the size of the arrow is then derived through the remaining space.

The background color of the loader is given through `--inactive-color` and the actual animation color is defined through `--active-color`.

```scss
.downloader {
  --size: 5rem;
  --bar-height: 6%;
  --bar-arrow-spacing: 10%;
  --arrow-height: calc(100% - var(--bar-height) - var(--bar-arrow-spacing));

  --inactive-color: rgba(255, 255, 255, 0.2);
  --active-color: white;
  
  width: var(--size);
}
```

The basic layout for the downloader is defined as a flex box operating in column mode:

```scss
.downloader {
  ...

  display: flex;
  flex-direction: column;
}
```

## Creating the Arrow Shape

The arrow shape is created by using a `clip-path` that crops the `.arrow` element to have it's arrowy shape. So it's also easy to customize and you can give it almost every shape you want.

```scss
.downloader {
  ...

  .arrow {
    background-color: var(--inactive-color);
    padding-top: var(--arrow-height);
    position: relative;
    
    clip-path: polygon(
      47% 0%, 
      53% 0%, 
      53% 85%, 
      80% 56%, 
      80% 67%, 
      50% 100%, 
      20% 67%, 
      20% 56%, 
      47% 85%
    );
  }
}
```

In order to create the animation an `:after` pseudo element is created inside the arrow, so it's also affected by the `clip-path` and it will be running from top to bottom, which is why it's fixed to the top (see `bottom: 100%;`) at the beginning.

```scss
.downloader {
  ...

  .arrow {
    ...
    
    &:after {
      content: "";
      position: absolute;
      background-color: var(--active-color);
      left: 0;
      right: 0;
      bottom: 100%;
      top: 0;
    }
  }
}
```

## Configuring the Indefinite Mode

So, for the indefinite mode the arrow's `:after` element is given an animation, that makes it run from top to bottom:


```scss
.downloader {
  ...

  &.indefinite {
    .arrow:after {
      animation: 2s loading-vertical ease-in-out infinite;
    }
  }
}

@keyframes loading-vertical {
  0% {
    top: 0%;
    bottom: 100%;
  }
  30% {
    top: 0%;
    bottom: 100%;
  }
  50% {
    top: 0%;
    bottom: 0%;
  }
  70% {
    top: 0%;
    bottom: 0%;
  }
  100% {
    top: 100%;
    bottom: 0%;
  }
}
```

## And same goes for the bar

Now, for the bar we're going to do the same, except that its size and animation direction differs:    

```scss
.downloader {
  ...

  .bar {
    position: relative;
    width: 100%;
    padding-top: var(--bar-height);
    margin-top: var(--bar-arrow-spacing);
    background-color: var(--inactive-color);
    
    &:after {
      content: "";
      position: absolute;
      background: var(--active-color);
      left: 0;
      right: 100%;
      bottom: 0;
      top: 0;
    }
  }

  &.indefinite {
    ...

    .bar:after {
      animation: 2s loading-horizontal ease-in-out infinite;
    }
  }
}

...

@keyframes loading-horizontal {
  0% {
    left: 0%;
    right: 100%;
  }
  30% {
    left: 0%;
    right: 100%;
  }
  50% {
    left: 0%;
    right: 0%;
  }
  70% {
    left: 0%;
    right: 0%;
  }
  100% {
    left: 100%;
    right: 0%;
  }
}
```


## Making the Definite Mode Work

Now, all that's required for the definite mode to work is the configuration of the `.definite` class. The arrow will keep its animation and the `.bar:after`'s right property is calculated through the `--percentage` custom property.

```scss
.downloader {
  ...


  &.definite {
    .arrow:after {
      animation: 2s loading-vertical ease-in-out infinite;
    }
    
    .bar:after {
      transition: 250ms right ease-in-out;
      right: calc(100% - var(--percentage));
    }
  }
}
```