Create Animated Download button in CSS & jQuery
Are you looking for an animated download button then in this post I am going to share simple jQuery and CSS based animated download button which you can use on your website for downloading files with some cool animation.
HTML
<div class="container"> <a href="" class="button"> <ul> <li>Download</li> <li>Downloading</li> <li>Open File</li> </ul> <div> <svg viewBox="0 0 24 24"></svg> </div> </a> <a href="" class="button dark-single"> <div> <svg viewBox="0 0 24 24"></svg> </div> </a> <div></div> <a href="" class="button white-single"> <div> <svg viewBox="0 0 24 24"></svg> </div> </a> <a href="" class="button dark"> <ul> <li>Download</li> <li>Downloading</li> <li>Open File</li> </ul> <div> <svg viewBox="0 0 24 24"></svg> </div> </a> </div> <!-- dribbble --> <a class="dribbble" href="https://dribbble.com/shots/7299868-Download-Buttons" target="_blank"><img src="https://cdn.dribbble.com/assets/dribbble-ball-mark-2bd45f09c2fb58dbbfb44766d5d1d07c5a12972d602ef8b32204d28fa3dda554.svg" alt=""></a> |
CSS
.button { &.dark-single { --background: none; --rectangle: #242836; --success: #4BC793; } &.white-single { --background: none; --rectangle: #F5F9FF; --arrow: #275efe; --success: #275efe; --shadow: rgba(10, 22, 50, .1); } &.dark { --background: #242836; --rectangle: #1C212E; --arrow: #F5F9FF; --text: #F5F9FF; --success: #2F3545; } } .button { --background: #275efe; --rectangle: #184fee; --success: #{mix(white, #184fee, 20%)}; --text: #fff; --arrow: #fff; --checkmark: #fff; --shadow: rgba(10, 22, 50, .24); display: flex; overflow: hidden; text-decoration: none; -webkit-mask-image: -webkit-radial-gradient(white, black); background: var(--background); border-radius: 8px; box-shadow: 0 2px 8px -1px var(--shadow); transition: transform .2s ease, box-shadow .2s ease; &:active { transform: scale(.95); box-shadow: 0 1px 4px -1px var(--shadow); } ul { margin: 0; padding: 16px 40px; list-style: none; text-align: center; position: relative; backface-visibility: hidden; font-size: 16px; font-weight: 500; line-height: 28px; color: var(--text); li { &:not(:first-child) { top: 16px; left: 0; right: 0; position: absolute; } &:nth-child(2) { top: 76px; } &:nth-child(3) { top: 136px; } } } & > div { position: relative; width: 60px; height: 60px; background: var(--rectangle); &:before, &:after { content: ''; display: block; position: absolute; } &:before { border-radius: 1px; width: 2px; top: 50%; left: 50%; height: 17px; margin: -9px 0 0 -1px; background: var(--arrow); } &:after { width: 60px; height: 60px; transform-origin: 50% 0; border-radius: 0 0 80% 80%; background: var(--success); top: 0; left: 0; transform: scaleY(0); } svg { display: block; position: absolute; width: 20px; height: 20px; left: 50%; top: 50%; margin: -9px 0 0 -10px; fill: none; z-index: 1; stroke-width: 2px; stroke: var(--arrow); stroke-linecap: round; stroke-linejoin: round; } } &.loading { ul { animation: text calc(var(--duration) * 1ms) linear forwards calc(var(--duration) * .065ms); } & > div { &:before { animation: line calc(var(--duration) * 1ms) linear forwards calc(var(--duration) * .065ms); } &:after { animation: background calc(var(--duration) * 1ms) linear forwards calc(var(--duration) * .065ms); } svg { animation: svg calc(var(--duration) * 1ms) linear forwards calc(var(--duration) * .065ms); } } } } @keyframes text { 10%, 85% { transform: translateY(-100%); } 95%, 100% { transform: translateY(-200%); } } @keyframes line { 5%, 10% { transform: translateY(-30px); } 40% { transform: translateY(-20px); } 65% { transform: translateY(0); } 75%, 100% { transform: translateY(30px); } } @keyframes svg { 0%, 20% { stroke-dasharray: 0; stroke-dashoffset: 0; } 21%, 89% { stroke-dasharray: 26px; stroke-dashoffset: 26px; stroke-width: 3px; margin: -10px 0 0 -10px; stroke: var(--checkmark); } 100% { stroke-dasharray: 26px; stroke-dashoffset: 0; margin: -10px 0 0 -10px; stroke: var(--checkmark); } 12% { opacity: 1; } 20%, 89% { opacity: 0; } 90%, 100% { opacity: 1; } } @keyframes background { 10% { transform: scaleY(0); } 40% { transform: scaleY(.15); } 65% { transform: scaleY(.5); border-radius: 0 0 50% 50%; } 75% { border-radius: 0 0 50% 50%; } 90%, 100% { border-radius: 0; } 75%, 100% { transform: scaleY(1); } } html { box-sizing: border-box; -webkit-font-smoothing: antialiased; } * { box-sizing: inherit; &:before, &:after { box-sizing: inherit; } } // Center & dribbble body { min-height: 100vh; display: flex; font-family: 'Roboto', Arial; justify-content: center; align-items: center; background: #E4ECFA; .container { display: flex; flex-wrap: wrap; justify-content: center; & > div { flex-basis: 100%; width: 0; } .button { margin: 16px; @media(max-width: 400px) { margin: 12px; } } } .dribbble { position: fixed; display: block; right: 20px; bottom: 20px; img { display: block; height: 28px; } } } |
JS
$('.button').each(function(e) { let duration = 3000, btn = $(this), svg = btn.find('svg'), svgPath = new Proxy({ y: null, smoothing: null }, { set(target, key, value) { target[key] = value; if(target.y !== null && target.smoothing !== null) { svg.html(getPath(target.y, target.smoothing, null)) } return true; }, get(target, key) { return target[key]; } }); btn.css('--duration', duration); svgPath.y = 20; svgPath.smoothing = 0; btn.on('click', e => { if(!btn.hasClass('loading')) { btn.addClass('loading'); TweenMax.to(svgPath, duration * .065 / 1000, { smoothing: .3 }); TweenMax.to(svgPath, duration * .265 / 1000, { y: 12, ease: Elastic.easeOut.config(1.12, .4) }).delay(duration * .065 / 1000); setTimeout(() => { svg.html(getPath(0, 0, [ [3, 14], [8, 19], [21, 6] ])); }, (duration / 2)); } return false; }); }); function getPoint(point, i, a, smoothing) { let cp = (current, previous, next, reverse) => { let p = previous || current, n = next || current, o = { length: Math.sqrt(Math.pow(n[0] - p[0], 2) + Math.pow(n[1] - p[1], 2)), angle: Math.atan2(n[1] - p[1], n[0] - p[0]) }, angle = o.angle + (reverse ? Math.PI : 0), length = o.length * smoothing; return [current[0] + Math.cos(angle) * length, current[1] + Math.sin(angle) * length]; }, cps = cp(a[i - 1], a[i - 2], point, false), cpe = cp(point, a[i - 1], a[i + 1], true); return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`; } function getPath(update, smoothing, pointsNew) { let points = pointsNew ? pointsNew : [ [4, 12], [12, update], [20, 12] ], d = points.reduce((acc, point, i, a) => i === 0 ? `M ${point[0]},${point[1]}` : `${acc} ${getPoint(point, i, a, smoothing)}`, ''); return `<path d="${d}" />`; } |
See live demo and download source code.
DEMO | DOWNLOAD
This awesome script developed by aaroniker. Visit their official repository for more information and follow for future updates.