<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));
This Pen doesn't use any external CSS resources.