<div class="volume">
    <svg class="shape" viewBox="0 0 64 88">
        <polyline points="60 4 36 24 4 24 4 64 36 64 60 84"></polyline>
    </svg>
    <svg class="first" viewBox="0 0 20 88"></svg>
    <svg class="second" viewBox="0 0 20 60"></svg>
    <svg class="third" viewBox="0 0 20 60"></svg>
</div>

<!-- dribbble -->
<a class="dribbble" href="https://dribbble.com/shots/7707657-Volume-Toggle" target="_blank"><img src="https://cdn.dribbble.com/assets/dribbble-ball-mark-2bd45f09c2fb58dbbfb44766d5d1d07c5a12972d602ef8b32204d28fa3dda554.svg" alt=""></a>
.volume {
    --line: #275EFE;
    --line-width: 7px;
    position: relative;
    cursor: pointer;
    padding-right: 48px;
    -webkit-tap-highlight-color: transparent;
    svg {
        display: block;
        fill: none;
        stroke: var(--line);
        stroke-width: var(--line-width);
        stroke-linecap: round;
        stroke-linejoin: round;
        &:not(.shape) {
            --scale: 1;
            --top: 0;
            --left: 50px;
            --height: 88px;
            position: absolute;
            top: var(--top);
            left: var(--left);
            width: 20px;
            height: var(--height);
            transform: scaleY(var(--scale));
        }
        &.shape {
            width: 64px;
            height: 88px;
        }
        &.second,
        &.third {
            --top: 14px;
            --height: 60px;
        }
        &.second {
            --left: 72px;
            --scale: .84;
        }
        &.third {
            --left: 92px;
            --scale: 1.16;
        }
    }
}

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;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    position: relative;
    background: #E8EBFB;
    .dribbble {
        position: fixed;
        display: block;
        right: 20px;
        bottom: 20px;
        img {
            display: block;
            height: 28px;
        }
    }
}
View Compiled
$('.volume').each(function(e) {

    let volume = $(this),
        svg = volume.find('svg:not(.shape)'),
        proxies = [];

    svg.each(function(i) {
        let svg = $(this);
        proxies[i] = new Proxy({ x: null }, {
            set(target, key, value) {
                target[key] = value;
                if(target.x !== null) {
                    svg.html(getPath(target.x, svg.height()));
                }
                return true;
            },
            get(target, key) {
                return target[key];
            }
        });
        proxies[i].x = 10;
    });

    proxies[1].x = 12;
    proxies[2].x = 15;

    let timeline = new TimelineMax({
        paused: true
    }).to(svg.eq(1), .4, {
        x: 8
    }).to(svg.eq(1), .3, {
        x: -22,
        scaleY: 1,
        ease: Power3.easeOut
    }).to(svg.eq(1), .3, {
        x: 20
    }).to(svg.eq(1), .8, {
        rotation: 135,
        ease: Elastic.easeOut.config(1, .4)
    }, .9);

    timeline.to(proxies[1], .2, {
        x: 6
    }, .5).to(proxies[1], .2, {
        x: 10
    }, .7).to(proxies[2], .2, {
        x: 6
    }, .5).to(proxies[2], .2, {
        x: 10
    }, .7);

    timeline.to(svg.eq(2), .4, {
        x: 8
    }, 0).to(svg.eq(2), .3, {
        x: -42,
        scaleY: 1,
        ease: Power3.easeOut
    }, .4).to(svg.eq(2), .3, {
        x: 0
    }, .7).to(svg.eq(2), .8, {
        rotation: 225,
        ease: Elastic.easeOut.config(1, .4)
    }, .9);

    volume.on('click touch', e => {
        TweenMax.to(proxies[0], volume.hasClass('muted') ? .12 : .2, {
            x: 4,
            repeat: 1,
            yoyo: true
        }).delay(volume.hasClass('muted') ? .95 : .5);
        volume.hasClass('muted') ? timeline.reverse() : timeline.play();
        volume.toggleClass('muted');
    })

});

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, height) {
    let smoothing = .2,
        points = [
            [10, 4],
            [update, height / 2],
            [10, height - 4]
        ],
        d = points.reduce((acc, point, i, a) => i === 0 ? `M ${point[0]},${point[1]}` : `${acc} ${getPoint(point, i, a, smoothing)}`, '');
    return `<path d="${d}" />`;
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://code.jquery.com/jquery-3.4.1.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TimelineMax.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js