Красивая кнопка с эффектом bubble

Для содания анимации будем использовать библиотеку TweenMax.

See the Pen Button bubble effect by stvoler (@stvoler) on CodePen.


<div>
<span class="button--bubble__container">
  <a href="#" class="button button--bubble">
    Юхууу!
  </a>
  <span class="button--bubble__effect-container">
    <span class="circle top-left"></span>
    <span class="circle top-left"></span>
    <span class="circle top-left"></span>
    <span class="button effect-button"></span>
    <span class="circle bottom-right"></span>
    <span class="circle bottom-right"></span>
    <span class="circle bottom-right"></span>
  </span>
</span>
</div>

$dark-blue: #222;
$green: #90feb5;
$action-color: $green;
* {
    box-sizing: border-box;
}

div {
    display: block;
    height: 100%;
    animation: hue-rotate 10s linear infinite;
}

.button {
    -webkit-font-smoothing: antialiased;
    background-color: $dark-blue;
    border: none;
    color: #fff;
    display: inline-block;
    font-family: Arial, sans-serif;
    font-size: 14px;
    font-weight: 700;
    text-decoration: none;
    user-select: none;
    letter-spacing: 1px;
    color: white;
    padding: 20px 40px;
    text-transform: uppercase;
    transition: all 0.1s ease-out;
    border-radius: 8px;
    &:hover {
        background-color: $action-color;
        color: #fff;
    }
    &:active {
        transform: scale(0.95);
    }
    &--bubble {
        position: relative;
        z-index: 2;
        color: white;
        background: none;
        &:hover {
            background: none;
        }
        &:hover + .button--bubble__effect-container .circle {
            background: darken($action-color, 15%);
        }
        &:hover + .button--bubble__effect-container .button {
            background: darken($action-color, 15%);
        }
        &:active + .button--bubble__effect-container {
            transform: scale(0.95);
        }
        &__container {
            position: relative;
            display: inline-block;
            .effect-button {
                position: absolute;
                width: 50%;
                height: 25%;
                top: 50%;
                left: 25%;
                z-index: 1;
                transform: translateY(-50%);
                background: $dark-blue;
                transition: background 0.1s ease-out;
            }
        }
    }
}

.button--bubble__effect-container {
    position: absolute;
    display: block;
    width: 200%;
    height: 400%;
    top: -150%;
    left: -50%;
    -webkit-filter: url("#goo");
    filter: url("#goo");
    transition: all 0.1s ease-out;
    pointer-events: none;
    .circle {
        position: absolute;
        width: 25px;
        height: 25px;
        border-radius: 15px;
        background: $dark-blue;
        transition: background 0.1s ease-out;
        &.top-left {
            top: 40%;
            left: 27%;
        }
        &.bottom-right {
            bottom: 40%;
            right: 27%;
        }
    }
}

.goo {
    position: absolute;
    visibility: hidden;
    width: 1px;
    height: 1px;
}

html,
body {
    width: 100%;
    height: 100%;
    text-align: center;
}

.button--bubble__container {
    top: 50%;
    margin-top: -25px;
}

@keyframes hue-rotate {
    from {
        -webkit-filter: hue-rotate(0);
        -moz-filter: hue-rotate(0);
        -ms-filter: hue-rotate(0);
        filter: hue-rotate(0);
    }
    to {
        -webkit-filter: hue-rotate(360deg);
        -moz-filter: hue-rotate(360deg);
        -ms-filter: hue-rotate(360deg);
        filter: hue-rotate(360deg);
    }
}

$('.button--bubble').each(function () {
    var $circlesTopLeft = $(this).parent().find('.circle.top-left');
    var $circlesBottomRight = $(this).parent().find('.circle.bottom-right');

    var tl = new TimelineLite();
    var tl2 = new TimelineLite();

    var btTl = new TimelineLite({
        paused: true
    });

    tl.to($circlesTopLeft, 1.2, {
        x: -25,
        y: -25,
        scaleY: 2,
        ease: SlowMo.ease.config(0.1, 0.7, false)
    });
    tl.to($circlesTopLeft.eq(0), 0.1, {
        scale: 0.2,
        x: '+=6',
        y: '-=2'
    });
    tl.to($circlesTopLeft.eq(1), 0.1, {
        scaleX: 1,
        scaleY: 0.8,
        x: '-=10',
        y: '-=7'
    }, '-=0.1');
    tl.to($circlesTopLeft.eq(2), 0.1, {
        scale: 0.2,
        x: '-=15',
        y: '+=6'
    }, '-=0.1');
    tl.to($circlesTopLeft.eq(0), 1, {
        scale: 0,
        x: '-=5',
        y: '-=15',
        opacity: 0
    });
    tl.to($circlesTopLeft.eq(1), 1, {
        scaleX: 0.4,
        scaleY: 0.4,
        x: '-=10',
        y: '-=10',
        opacity: 0
    }, '-=1');
    tl.to($circlesTopLeft.eq(2), 1, {
        scale: 0,
        x: '-=15',
        y: '+=5',
        opacity: 0
    }, '-=1');

    var tlBt1 = new TimelineLite();
    var tlBt2 = new TimelineLite();

    tlBt1.set($circlesTopLeft, {
        x: 0,
        y: 0,
        rotation: -45
    });
    tlBt1.add(tl);

    tl2.set($circlesBottomRight, {
        x: 0,
        y: 0
    });
    tl2.to($circlesBottomRight, 1.1, {
        x: 30,
        y: 30,
        ease: SlowMo.ease.config(0.1, 0.7, false)
    });
    tl2.to($circlesBottomRight.eq(0), 0.1, {
        scale: 0.2,
        x: '-=6',
        y: '+=3'
    });
    tl2.to($circlesBottomRight.eq(1), 0.1, {
        scale: 0.8,
        x: '+=7',
        y: '+=3'
    }, '-=0.1');
    tl2.to($circlesBottomRight.eq(2), 0.1, {
        scale: 0.2,
        x: '+=15',
        y: '-=6'
    }, '-=0.2');
    tl2.to($circlesBottomRight.eq(0), 1, {
        scale: 0,
        x: '+=5',
        y: '+=15',
        opacity: 0
    });
    tl2.to($circlesBottomRight.eq(1), 1, {
        scale: 0.4,
        x: '+=7',
        y: '+=7',
        opacity: 0
    }, '-=1');
    tl2.to($circlesBottomRight.eq(2), 1, {
        scale: 0,
        x: '+=15',
        y: '-=5',
        opacity: 0
    }, '-=1');

    tlBt2.set($circlesBottomRight, {
        x: 0,
        y: 0,
        rotation: 45
    });
    tlBt2.add(tl2);

    btTl.add(tlBt1);
    btTl.to($(this).parent().find('.button.effect-button'), 0.8, {
        scaleY: 1.1
    }, 0.1);
    btTl.add(tlBt2, 0.2);
    btTl.to($(this).parent().find('.button.effect-button'), 1.8, {
        scale: 1,
        ease: Elastic.easeOut.config(1.2, 0.4)
    }, 1.2);

    btTl.timeScale(2.6);

    $(this).on('mouseover', function () {
        btTl.restart();
    });
});

Комментарии ()