WEBLEB
Home
Editor
Login
Pro
English
English
Français
Español
Português
Deutsch
Italiano
हिंदी
Animated Download Button
6704
webleb
Publish Your Code
Recommended
15 October 2024
Dark Mode And Night Mode Button
2 August 2024
Animated Portfolio
3 March 2025
Download button
index.html
Copy
Webleb
Download
Downloading
Open File
styles.css
Copy
.button.dark { --background: #242836; --rectangle: #1c212e; --arrow: #f5f9ff; --text: #f5f9ff; --success: #2f3545; } .button { --background: #275efe; --rectangle: #184fee; --success: #4672f1; --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 0.2s ease, box-shadow 0.2s ease; } .button:active { transform: scale(0.95); box-shadow: 0 1px 4px -1px var(--shadow); } .button 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); } .button ul li:not(:first-child) { top: 16px; left: 0; right: 0; position: absolute; } .button ul li:nth-child(2) { top: 76px; } .button ul li:nth-child(3) { top: 136px; } .button > div { position: relative; width: 60px; height: 60px; background: var(--rectangle); } .button > div:before, .button > div:after { content: ''; display: block; position: absolute; } .button > div:before { border-radius: 1px; width: 2px; top: 50%; left: 50%; height: 17px; margin: -9px 0 0 -1px; background: var(--arrow); } .button > div: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); } .button > div 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; } .button.loading ul { animation: text calc(var(--duration) * 1ms) linear forwards calc(var(--duration) * .065ms); } .button.loading > div:before { animation: line calc(var(--duration) * 1ms) linear forwards calc(var(--duration) * .065ms); } .button.loading > div:after { animation: background calc(var(--duration) * 1ms) linear forwards calc(var(--duration) * .065ms); } .button.loading > div 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(0.15); } 65% { transform: scaleY(0.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; } body { min-height: 100vh; display: flex; font-family: 'Roboto', Arial; justify-content: center; align-items: center; background: linear-gradient(180deg, #21231f 0%, #247b8f 100%); overflow-y: hidden; } body .container { display: flex; flex-wrap: wrap; justify-content: center; } body .container > div { flex-basis: 100%; width: 0; } body .container .button { margin: 16px; } @media (max-width: 400px) { body .container .button { margin: 12px; } }
main.js
Copy
document.querySelectorAll('.button').forEach(button => { let duration = 3000, svg = button.querySelector('svg'), svgPath = new Proxy({ y: null, smoothing: null }, { set(target, key, value) { target[key] = value; if(target.y !== null && target.smoothing !== null) { svg.innerHTML = getPath(target.y, target.smoothing, null); } return true; }, get(target, key) { return target[key]; } }); button.style.setProperty('--duration', duration); svgPath.y = 20; svgPath.smoothing = 0; button.addEventListener('click', e => { e.preventDefault(); if(!button.classList.contains('loading')) { button.classList.add('loading'); gsap.to(svgPath, { smoothing: .3, duration: duration * .065 / 1000 }); gsap.to(svgPath, { y: 12, duration: duration * .265 / 1000, delay: duration * .065 / 1000, ease: Elastic.easeOut.config(1.12, .4) }); setTimeout(() => { svg.innerHTML = getPath(0, 0, [ [3, 14], [8, 19], [21, 6] ]); }, duration / 2); } }); }); 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 `
`; }