<main class="flexbox">
  <div class="button-wrapper link">
    <button type="button" class="button btn-primary"><i class="uil uil-moonset"></i> Goodnight<div class="btn-secondary"></div></button>
  </div>
</main>

<div class="cursor"></div>
/* -
-*-~*~-*-*-~*~-*-*-~*~* |
●▬▬▬▬▬▬▬๑۩۩๑▬▬▬▬▬▬▬●
Made by ~
Areal Alien ❥ 雷克斯
●▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬●
──────▄▀▄─────▄▀▄
─────▄█░░▀▀▀▀▀░░█▄
─▄▄──█░░░░░░░░░░░█──▄▄
█▄▄█─█░░▀░░┬░░▀░░█─█▄▄█
-*-~*~-*-*-~*~-*-*-~*~* |
- */
:root {
    --bc: #0e0d0f;
    --primary: rgb(161, 166, 252);
    --white: #ffffff;
    --black: #000000;
    /* Colors */
    --red: #da2c4d;
    --orange: #fd7e14;
    --yellow: #f8ab37;
    --yellow-bright: #ffc107;
    --light-green: #24e33a;
    --green: #28a745;
    --teal: #20c997;
    --cyan: #17a2b8;
    --blue: #007bff;
    --indigo: #6610f2;
    --purple: #6f42c1;
    --pink: #e83e8c;
    /* Gray Colors */
    --bc-gray: #ede8e4;
    --gray: #9e9d9b;
    --gray-dark: #1c1a19;
    /* Gradients */
    --rainbow: linear-gradient(90deg, rgba(245,96,117,1) 0%, rgba(252,210,29,1) 14%, rgba(246,237,105,1) 28%, rgba(127,246,105,1) 43%, rgba(105,246,176,1) 55%, rgba(105,231,246,1) 69%, rgba(105,150,246,1) 85%, rgba(150,105,246,1) 100%);
    /* Sizes */
    --button: 1.22rem;
    /* Fonts */
    --font-main: "Poppins";
}
* {
    box-sizing: border-box;
    user-select: none;
    cursor: none;
}
html, body {
    margin: 0;
    width: 100%;
    font-family: var(--font-main);
    background-color: var(--bc);
    -webkit-font-smoothing: antialiased;
    scroll-behavior: smooth;
}
main {
    height: 100vh;
}
/* Global classes */
.flexbox {
    display: flex;
    justify-content: center;
    align-items: center;
}
/* Button 1 */
.button-wrapper {
    margin: 1em 0;
}
.button-svg {
    fill: var(--white);
    height: calc(var(--button) - .1rem);
}
.button, .btn-secondary {
    margin: 0;
    width: 100%;
    position: relative;
    padding: 1.2em 1.8em;
    letter-spacing: .1em;
    text-align: center;
    color: var(--bc);
    font-size: var(--button);
    background: var(--rainbow);
    background-size: 500%;
    border-radius: 5em;
    border: none;
    transform: scaleX(1);
    transition: transform .3s cubic-bezier(.175,.885,.32,1.275), filter .3s cubic-bezier(.175,.885,.32,1.275), bottom .3s cubic-bezier(.175,.885,.32,1.275), background-position 3s cubic-bezier(.455,.03,.515,.955), -webkit-transform .3s cubic-bezier(.175,.885,.32,1.275), -webkit-filter .3s cubic-bezier(.175,.885,.32,1.275);
}
.button {
    transition: transform .3s cubic-bezier(.175,.885,.32,1.275), bottom .3s cubic-bezier(.175,.885,.32,1.275), background-position 3s cubic-bezier(.455,.03,.515,.955), -webkit-transform .3s cubic-bezier(.175,.885,.32,1.275);
}
.button, .button .btn-secondary {
    background-position: 0 50%;
    bottom: 0;
}
.button .btn-secondary {
    left: 0;
    width: 100%;
    position: absolute;
    filter: blur(1rem);
    opacity: .65;
    z-index: -1;
    transform: scale3d(.85, .85, 1);
    transition: transform .3s cubic-bezier(.175,.885,.32,1.275), filter .3s cubic-bezier(.175,.885,.32,1.275), bottom .3s cubic-bezier(.175,.885,.32,1.275), background-position 3s cubic-bezier(.455,.03,.515,.955), -webkit-transform .3s cubic-bezier(.175,.885,.32,1.275), -webkit-filter .3s cubic-bezier(.175,.885,.32,1.275);
}
.button:focus {
    outline: none;
}
.button:hover {
    transform: scale3d(1.1, 1.1, 1);
    background-position: 100% 50%;
    outline: none;
    bottom: 2px;
}
.btn-secondary, .button:hover .btn-secondary {
    background-position: 100% 50%;
    filter: blur(1.6rem);
    bottom: -5px;
}
/* Ripple */
span.ripple {
    position: absolute;
    border-radius: 50%;
    transform: scale(0);
    animation: ripple 600ms linear;
    background-color: rgba(255, 255, 255, .85);
}
/* Ripple Animation */
@keyframes ripple {
    to {
        transform: scale(.65);
        opacity: 0;
    }
}
/* Cursor */
.cursor {
    position: fixed;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background-color: #f5f5f5;
    pointer-events: none;
    mix-blend-mode: difference;
    transition: transform .3s cubic-bezier(.175, .885, .32, 1.175);
    z-index: 999;
}
$(document).ready(function() {

    var cursor = $(".cursor");

    $(window).mousemove(function(e) {
        cursor.css({
            top: e.clientY - cursor.height() / 2,
            left: e.clientX - cursor.width() / 2
        });
    });

    $(window)
        .mouseleave(function() {
            cursor.css({
                opacity: "0"
            });
        })
        .mouseenter(function() {
            cursor.css({
                opacity: "1"
            });
        });

    $(".link")
        .mouseenter(function() {
            cursor.css({
                transform: "scale(3.2)"
            });
        })
        .mouseleave(function() {
            cursor.css({
                transform: "scale(1)"
            });
        });

    $(window)
        .mousedown(function() {
            cursor.css({
                transform: "scale(.2)"
            });
        })
        .mouseup(function() {
            cursor.css({
                transform: "scale(1)"
            });
        });
});

let updateScrollPos = function (e) {
    $(window).scrollTop($(window).scrollTop() + (clickY - e.pageY));
}

class Button {
    constructor(HTMLButtonElement) {
        this.button = HTMLButtonElement;
        this.width = this.button.offsetWidth;
        this.height = this.button.offsetHeight;
        this.left = this.button.offsetLeft;
        this.top = this.button.offsetTop;
        this.x = 0;
        this.y = 0;
        this.cursorX = 0;
        this.cursorY = 0;
        this.magneticPullX = 0.4;
        this.magneticPullY = 0.9;
        this.isHovering = false;
        this.magnetise();
        this.createRipple();
    }

    onEnter = () => {
        gsap.to(this.button, 0.4, {
            x: this.x * this.magneticPullX,
            y: this.y * this.magneticPullY,
            ease: Power4.easeOut
        });
    };

    onLeave = () => {
        gsap.to(this.button, 0.7, {
            x: 0,
            y: 0,
            ease: Elastic.easeOut.config(1.1, 0.5)
        });
    };

    magnetise = () => {
        document.querySelector("body").addEventListener("mousemove", (e) => {
            this.cursorX = e.clientX;
            this.cursorY = e.clientY;

            const center = {
                x: this.left + this.width / 2,
                y: this.top + this.height / 2
            };

            this.x = this.cursorX - center.x;
            this.y = this.cursorY - center.y;

            const distance = Math.sqrt(this.x * this.x + this.y * this.y);
            const hoverArea = this.isHovering ? 0.6 : 0.5;

            if (distance < this.width * hoverArea) {
                if (!this.isHovering) {
                    this.isHovering = true;
                }
                this.onEnter();
            } else {
                if (this.isHovering) {
                    this.onLeave();
                    this.isHovering = false;
                }
            }
        });
    };

    createRipple = () => {
        this.button.addEventListener("click", () => {
            const circle = document.createElement("span");
            const diameter = Math.max(
                this.button.clientWidth,
                this.button.clientHeight
            );
            const radius = diameter / 2;

            const offsetLeft = this.left + this.x * this.magneticPullX;
            const offsetTop = this.top + this.y * this.magneticPullY;

            circle.style.width = circle.style.height = `${diameter}px`;
            circle.style.left = `${this.cursorX - offsetLeft - radius}px`;
            circle.style.top = `${this.cursorY - offsetTop - radius}px`;
            circle.classList.add("ripple");

            const ripple = this.button.getElementsByClassName("ripple")[0];

            if (ripple) {
                ripple.remove();
            }

            this.button.appendChild(circle);
        });
    };
}

const buttons = document.getElementsByTagName("button");
for (const button of buttons) {
    new Button(button);
}

External CSS

  1. https://unicons.iconscout.com/release/v3.0.0/css/line.css
  2. https://unicons.iconscout.com/release/v3.0.0/css/solid.css
  3. https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&amp;display=swap

External JavaScript

  1. https://code.jquery.com/jquery-3.5.1.js
  2. https://code.jquery.com/ui/1.12.1/jquery-ui.js
  3. https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js