Downloadknop met voortgang New
A download button that shows its own progress after a click: the arrow makes way for a ring that fills up, with percentage and megabytes alongside, and ends in a check with the file name. You can stop while downloading; the state is announced via aria-live. For quotes, brochures, manuals and invoices as PDF; with reduced motion only the rising number remains.
Offerte dakkapel, Zwolle
How to use it
- Paste the HTML where the buttons should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Downloadknop met voortgang · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="kdl">
<div class="kdl__box">
<div class="kdl__file"><svg class="kdl__doc" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 2.5h8l4.5 4.5v14.5H6z"/><path d="M14 2.5V7h4.5"/></svg><div><p class="kdl__name">Offerte dakkapel, Zwolle</p><p class="kdl__meta">Pdf-bestand, 2,4 MB</p></div></div>
<div class="kdl__acts">
<button class="kdl__btn" type="button"><span class="kdl__ic" aria-hidden="true"><svg viewBox="0 0 24 24"><circle class="kdl__trk" cx="12" cy="12" r="10"/><circle class="kdl__arc" cx="12" cy="12" r="10" pathLength="100"/><g class="kdl__arrow"><path d="M12 6.5v9"/><path d="M8 12l4 4 4-4"/></g><path class="kdl__chk" d="M7.5 12.5l3 3 6-6.5" pathLength="100"/></svg></span><span class="kdl__lbl">Download offerte</span></button>
<button class="kdl__stop" type="button" hidden>Stoppen</button>
</div>
<p class="kdl__st" aria-live="polite"></p>
</div>
</div>
</div>/* Downloadknop met voortgang · NedDev · eigen werk. */
.kdl{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:14px;background:#f4f3f1;font-family:'Switzer',sans-serif;color:#0a0a0a}
.kdl *,.kdl *::before,.kdl *::after{box-sizing:border-box}
.kdl__box{width:min(330px,100%);padding:16px;background:#fff;border:1px solid #e2dfda;border-radius:8px}
.kdl__file{display:flex;align-items:center;gap:12px}
.kdl__doc{flex:none;width:30px;height:30px;fill:none;stroke:#0a0a0a;stroke-width:1.5;stroke-linejoin:round}
.kdl__name{margin:0;font:600 15px/1.25 'Switzer',sans-serif}
.kdl__meta{margin:2px 0 0;font:400 13px/1.3 'Switzer',sans-serif;color:#5d5953}
.kdl__acts{display:flex;align-items:center;gap:10px;margin-top:14px}
.kdl__btn{appearance:none;display:inline-flex;align-items:center;gap:10px;margin:0;padding:10px 16px 10px 12px;min-height:46px;border:0;border-radius:4px;background:#0a0a0a;color:#fff;font:600 14px/1 'Switzer',sans-serif;cursor:pointer;font-variant-numeric:tabular-nums;transition:background-color .2s ease,color .2s ease}
.kdl__btn:hover{background:#2b2926}
.kdl__btn:focus-visible,.kdl__stop:focus-visible{outline:2px solid #F5480F;outline-offset:3px}
.kdl__ic svg{display:block;width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.kdl__trk{stroke:rgba(255,255,255,.22);opacity:0;transition:opacity .2s ease}
.kdl__arc{stroke:#F5480F;stroke-dasharray:100;stroke-dashoffset:100;transform:rotate(-90deg);transform-origin:12px 12px;opacity:0;transition:opacity .2s ease}
.kdl__arrow{transition:transform .25s ease,opacity .2s ease}
.kdl__chk{stroke-dasharray:100;stroke-dashoffset:100;transition:stroke-dashoffset .35s cubic-bezier(.4,0,.2,1) .1s}
.kdl__btn:hover .kdl__arrow{transform:translateY(1.5px)}
.kdl.is-busy .kdl__btn{cursor:default;background:#0a0a0a}
.kdl.is-busy .kdl__trk,.kdl.is-busy .kdl__arc{opacity:1}
.kdl.is-busy .kdl__arrow{transform:scale(.62);animation:kdl-drop 1s ease-in-out infinite}
@keyframes kdl-drop{0%,100%{transform:translateY(-1px) scale(.62)}50%{transform:translateY(1.5px) scale(.62)}}
.kdl.is-done .kdl__btn{background:#F5480F;color:#0a0a0a}
.kdl.is-done .kdl__arrow{opacity:0}
.kdl.is-done .kdl__chk{stroke-dashoffset:0}
.kdl__stop{appearance:none;margin:0;padding:10px 12px;min-height:46px;border:1px solid #c9c5be;border-radius:4px;background:#fff;color:#0a0a0a;font:500 14px/1 'Switzer',sans-serif;cursor:pointer;transition:border-color .16s ease}
.kdl__stop:hover{border-color:#0a0a0a}
.kdl__st{min-height:18px;margin:10px 0 0;font:400 13px/1.35 'Switzer',sans-serif;color:#5d5953}
@media (prefers-reduced-motion:reduce){.kdl.is-busy .kdl__arrow{animation:none}.kdl__arrow,.kdl__chk,.kdl__trk,.kdl__arc,.kdl__btn{transition:none}}// Downloadknop met voortgang · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.kdl');if(!w)return;
var b=w.querySelector('.kdl__btn'),lbl=w.querySelector('.kdl__lbl'),arc=w.querySelector('.kdl__arc'),stop=w.querySelector('.kdl__stop'),st=w.querySelector('.kdl__st');
var TOT=2.4,p=0,raf=0,last=0,reset=0,lastSay=-1;
function nl(n){return n.toFixed(1).replace('.',',');}
function paint(){var pc=Math.floor(p*100);arc.style.strokeDashoffset=String(100-p*100);lbl.textContent=pc+'%';st.textContent=nl(TOT*p)+' van 2,4 MB';
var q=Math.floor(pc/25);if(q!==lastSay){lastSay=q;st.setAttribute('aria-live','polite');}}
function tick(t){if(!last)last=t;var dt=Math.min(64,t-last);last=t;
var speed=p<.2?.00022:p<.7?.00038:.00026;p=Math.min(1,p+dt*speed*(0.75+Math.random()*.5));paint();
if(p>=1){done();return;}raf=requestAnimationFrame(tick);}
function start(){if(w.classList.contains('is-busy'))return;clearTimeout(reset);w.classList.remove('is-done');p=0;last=0;lastSay=-1;
w.classList.add('is-busy');b.setAttribute('aria-disabled','true');stop.hidden=false;paint();raf=requestAnimationFrame(tick);}
function done(){w.classList.remove('is-busy');w.classList.add('is-done');b.removeAttribute('aria-disabled');stop.hidden=true;lbl.textContent='Gedownload';
st.textContent='offerte-dakkapel-zwolle.pdf staat in je downloads.';b.focus();
reset=setTimeout(function(){w.classList.remove('is-done');arc.style.strokeDashoffset='100';lbl.textContent='Opnieuw downloaden';},4200);}
function cancel(){cancelAnimationFrame(raf);w.classList.remove('is-busy');b.removeAttribute('aria-disabled');stop.hidden=true;arc.style.strokeDashoffset='100';
lbl.textContent='Download offerte';st.textContent='Download gestopt.';b.focus();}
b.addEventListener('click',function(){if(!w.classList.contains('is-busy'))start();});
stop.addEventListener('click',cancel);
}
init(document.querySelector('.jouw-container'));
More buttons
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →