CSS radial progress bar - Animate All the Things!

by Adithya Valsaraj

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/1.6.1/less.min.js"></script>
<div class="radial-progress" data-progress="75">
  <div class="circle">
    <div class="mask full">
      <div class="fill"></div>
    </div>
    <div class="mask half">
      <div class="fill"></div>
      <div class="fill fix"></div>
    </div>
    <div class="shadow"></div>
  </div>
  <div class="inset">
    <div class="percentage">
      <div class="numbers">75%</div>
    </div>
  </div>
</div>

SCSS

.radial-progress {
  @circle-size: 50px;
  @circle-background: #bdc3c7;
  @circle-color: #1abc9c;
  @inset-size: 35px;
  @inset-color: #eaeaea;
  @transition-length: 1s;
  @shadow: 6px 6px 5px rgba(0, 0, 0, 0.2);
  @percentage-color: #bdc3c7;
  @percentage-font-size: 14px;
  @percentage-text-width: 50px;
  width: @circle-size;
  height: @circle-size;
  background-color: @circle-background;
  border-radius: 50%;

  .circle {
    .mask,
    .fill,
    .shadow {
      width: @circle-size;
      height: @circle-size;
      position: absolute;
      border-radius: 50%;
    }

    .shadow {
      box-shadow: @shadow inset;
    }

    .mask,
    .fill {
      -webkit-backface-visibility: hidden;
      transition: -webkit-transform @transition-length;
      transition: -ms-transform @transition-length;
      transition: transform @transition-length;
      border-radius: 50%;
    }

    .mask {
      clip: rect(0px, @circle-size, @circle-size, @circle-size/2);

      .fill {
        clip: rect(0px, @circle-size/2, @circle-size, 0px);
        background-color: @circle-color;
      }
    }
  }

  .inset {
    width: @inset-size;
    height: @inset-size;
    position: absolute;
    margin-left: (@circle-size - @inset-size)/2;
    margin-top: (@circle-size - @inset-size)/2;
    background-color: @inset-color;
    border-radius: 50%;
    box-shadow: @shadow;

    .percentage {
      height: @percentage-font-size;
      width: @percentage-text-width;
      overflow: hidden;
      position: absolute;
      top: (@inset-size - @percentage-font-size) / 2;
      left: (@inset-size - @percentage-text-width) / 2;
      line-height: 1;

      .numbers {
        transition: width @transition-length;
        display: inline-block;
        vertical-align: top;
        text-align: center;
        font-size: @percentage-font-size;
        color: @percentage-color;
      }
    }
  }

  @i: 0;
  @increment: 180deg / 100;

  .loop (@i) when (@i <=100) {
    &[data-progress="@{i}"] {
     ...

JavaScript

$('head style[type="text/css"]').attr('type', 'text/less');
less.refreshStyles();
window.randomize = function() {
  $('.radial-progress').attr('data-progress', Math.floor(Math.random() * 100));
}