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.

Animated Download button

HTML

<div class="container">
 
    <a href="" class="button">
        <ul>
            <li>&#68;ownload</li>
            <li>&#68;ownloading</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>&#68;ownload</li>
            <li>&#68;ownloading</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.


Don’t forget to Subscribe My Public Notebook for more useful free scripts, tutorials and articles.