<h1 class="pen-title">Download button with progress indicator <a class="reset">reset</a></h1>

<div class="pen-wrapper">
  <div class="pen-wrapper__inner">
    
    <div class="button-wrapper">
      <button class="button">
        <span class="button__text button__text--download">
          Download
          <svg class="icon button__icon--cloud-download"><use xlink:href="#icon-cloud-download"></use></svg>
        </span>
      </button>
      <div class="pie-loader">
        <svg><circle r="40" cx="80" cy="80" /></svg>
      </div>
    </div>

  </div>
</div>

<svg style="position: absolute; width: 0; height: 0;" width="0" height="0" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <symbol id="icon-cloud-download" viewBox="0 0 1024 1024">
      <title>cloud-download</title>
      <path class="path1" d="M640 85.333q78 0 149.167 30.5t122.5 81.833 81.833 122.5 30.5 149.167q0 85-35 160.667t-96.667 129.167-140 77.5l21-20.667q18-18.333 28-42.667 9.333-22.667 9.333-49.333 0-6.667-0.333-9.333 59.333-41.333 93.833-105.833t34.5-139.5q0-60.667-23.667-116t-63.667-95.333-95.333-63.667-116-23.667q-55.333 0-106.5 19.833t-90 53.833-65 81.333-33.833 101h-88.667q-70.667 0-120.667 50t-50 120.667q0 38.667 15.167 71.667t39.833 54.167 54.833 33 60.833 11.833h50q11.667 29.333 30 48l37.667 37.333h-117.667q-69.667 0-128.5-34.333t-93.167-93.167-34.333-128.5 34.333-128.5 93.167-93.167 128.5-34.333h22q26.333-74.333 79.333-132.167t126.833-90.833 155.833-33zM554.667 426.667q17.667 0 30.167 12.5t12.5 30.167v281l55-55.333q12.333-12.333 30.333-12.333 18.333 0 30.5 12.167t12.167 30.5q0 18-12.333 30.333l-128 128q-12.333 12.333-30.333 12.333t-30.333-12.333l-128-128q-12.333-13-12.333-30.333 0-17.667 12.5-30.167t30.167-12.5q18 0 30.333 12.333l55 55.333v-281q0-17.667 12.5-30.167t30.167-12.5z"></path>
    </symbol>
    <symbol id="icon-checkmark" viewBox="0 0 1024 1024">
      <title>checkmark</title>
      <path class="path1" d="M864 128l-480 480-224-224-160 160 384 384 640-640z"></path>
    </symbol>
  </defs>
</svg>
// ----------------
// Variables
// ----------------
$bg: #81a687;
$blue: #3acaff;
$pink: #ff005a;
$pink-light: #ff4184;
$outer-height: 160px;
$outer-padding: 23px;
$btn-height: 114px;
$timing-function: ease;
$timing-speed: .5s;


* {
  box-sizing: border-box;
}

button {
  outline: none;
  cursor: pointer;
}
.icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  fill: currentColor;
}

body {
  font-family: 'Open Sans', sans-serif;
  font-size: 16px;
  color: #fff;
  background: linear-gradient(to right, #566a39 0%,#75986f 100%);
}

.pen-wrapper {
  display: flex;
  width: 100%;
  height: calc(100vh - 85px);
  justify-content: center;
  align-items: center;
}
.pen-title {
  text-align: center;
  font-size: 20px;
  line-height: 40px;
  padding: 20px 0;

  a {
    text-decoration: underline;
    font-size: .75em;
    cursor: pointer;
  }
}



// ----------------
// Button Wrapper
// ----------------
.button-wrapper {
  position: relative;
  display: inline-block;
  padding: $outer-padding;
  min-width: $outer-height;
  min-height: $outer-height;
  border-radius: $btn-height;
  box-shadow: 0px -2px 2px rgba(255, 255, 255, 0.22), 
              inset 0px -2px 6px rgba(0, 0, 0, 0.2);
  
  &.is_fixed_size {
    width: $outer-height;
    height: $outer-height;
  }
}


// ----------------
// Button 
// ----------------
.button {
  position: relative;
  height: $btn-height;
  min-width: $btn-height;
  padding: 0 34px;
  border-radius: ($btn-height / 2);
  box-shadow: inset 0px -1px 6px 0px rgba(255, 255, 255, 0.73);
  background: $pink;
  background: linear-gradient($pink-light 0%, $pink 100%, $pink 100%);
  border: none;
  font-size: 45px;
  color: white;
  line-height: $btn-height;
  font-weight: 700;

}


// ----------------
// Button text
// ----------------
.button__text {
  position: relative;
  display: block;
  height: $btn-height;
  white-space: nowrap;
  opacity: 1;
}

.button__text--download {
  width: 270px;
  transition: opacity $timing-speed $timing-function,
              width $timing-speed $timing-function;
  
  &.is_animated {
    overflow: hidden;
    width: 0px;
    opacity: 0;
  }
}

.button__text--progress {
  margin-right: -35px;
  margin-left: -35px;
  width: $btn-height;
  font-size: 40px;
  opacity: 0;
  transition: opacity $timing-speed $timing-function;
  
  sub {
    font-size: .5em;
    font-weight: normal;
  }

  &.is_animated {
    opacity: 1;
  }
}

.button__text--complete {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 999;
  border-radius: 50%;
  height: $btn-height;
  width: $btn-height;
  box-shadow: inset 0px -1px 6px 0px rgba(255, 255, 255, 0.73);
  background: $blue;
  transform: scale(1.5);
  transition: transform $timing-speed $timing-function;
  
  &.is_animated {
    transform: scale(1);
  }
}


.button__icon--cloud-download,
.button__icon--checkmark {
  position: relative;
  top: 7px;
}


// ----------------
// Pie loader
// ----------------
.pie-loader {
  position: absolute;
  top: 0; 
  left: 0;
  z-index: -1;
  width: $outer-height;
  height: $outer-height;
  opacity: 1;
  transition: opacity .1s $timing-function;
  
  svg {
    width: 100%;
    height: 100%;
  }
  circle {
    fill: $blue;
    stroke: $blue;
    stroke-width: ($outer-height / 2);
    stroke-dasharray: 0 252;
    transition: all .1s linear;
  }
  
  &.is_hidden {
    opacity: 0;
  }
}
View Compiled
;(function($){
  
  var btnStartTxt = '<span class="button__text button__text--download">Download <svg class="icon button__icon--cloud-download"><use xlink:href="#icon-cloud-download"></use></svg></span>';
  var btnProgressTxt = '<span class="button__text button__text--progress">0<sub>%</sub></span>';
  var btnEndTxt = '<span class="button__text button__text--complete"><svg class="icon button__icon--checkmark"><use xlink:href="#icon-checkmark"></use></svg></span>';

  var isActive = false;
  
  var stageStep = function( $el, delay, returnFunction ) {
    var delay = ( typeof delay !== 'undifined' ) ? delay : 0;
    setTimeout(function(){
      $el.addClass('is_animated');
    },10);
    if (typeof returnFunction === 'function') {
      setTimeout(function(){ 
        returnFunction();
      }, delay);
    }
  };

  var calcDownload = function(current) {
    // you can use this to add in your logic for calculating the progress of the download.
    // current == the current download percentage
    // return the current percentage of the download
    return current + (Math.floor(Math.random() * (2 - 0 + 1) + 0));
  };

  var initCounter = function($el, returnFunction) {
    var wrapper = $el.parent('div');
    var timerInterval = (1000 / 33);
    var counter = 0;
    var circle = (252 / 100);
    
    var timer = setInterval(function(){
      counter = calcDownload(counter);
      $('.button__text--progress', wrapper).html(counter+'<sub>%</sub>');
      $('.pie-loader circle', wrapper).css('stroke-dasharray', (counter * circle) + ' 252');
      if (counter === 100 || counter > 100 ) {
        clearTimeout(timer);
        $('.pie-loader', wrapper).addClass('is_hidden');
        returnFunction();
      }
    }, timerInterval);
  };


  function clickHandler() {
    if (isActive) {return;}

    isActive = true;
    var btn = $(this);

    stageStep( btn.find('.button__text--download'), 500, function(){
      btn.html(btnProgressTxt);
      btn.parent('div').addClass('is_fixed_size');
      stageStep( btn.find('.button__text--progress'), 500, function(){
        initCounter(btn, function(){
          btn.append(btnEndTxt);
          stageStep( btn.find('.button__text--complete'));
          btn.find('.button__text--progress').remove();
        });
      });
    });
  };

  function reset() {
    isActive = false;
    $('.button').html( btnStartTxt );
    $('.pie-loader').removeClass('is_hidden')
      .find('circle').removeAttr('style')
      .parents('.button-wrapper').removeClass('is_fixed_size');
  }

  $('.reset').on('click', reset);
  $('.button').on('click', clickHandler);

}(jQuery));

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js