<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@500&display=swap" rel="stylesheet">
<div id="dark-light-container">
    <div class="white-container">
        <button class="button"><span>Hover!</span></button>
    </div>
    <div class="black-container">
        <button class="button green" data-filter-color="rgba(71, 255, 111, 0.4)"><span>🔧 Work</span></button>
    </div>
    <div class="black-container">
        <button class="button animated" data-filter-color="#00a1ff57"><span>🐭 Mouse Over</span></button>
    </div>
    <div class="white-container">
        <button class="button purple" data-filter-color="#e347ff8f" data-custom-perspective="900px"><span>⚙️ Another Example</span></button>
    </div>
</div>
<a href="https://fjolt.com/article/css-javascript-3d-depth-hover-buttons" target="_blank">Read Article Here</a>
    body {
      margin: 0;
      background: rgb(10 13 37);
      padding: 0;
    }
    #dark-light-container {
        float: left;
        width: 100%;
        margin: 0 0 0 0;
    }
a {
  color: rgba(255,255,255,0.5);
  font-size: 1rem;
  font-family: Inter, sans-serif;
  border-top: 1px solid rgba(255,255,255,0.2);
  display: block;
  font-size: 1.25rem;
  padding: 1rem 1.5rem;
  float: left;
  width: 100%;
}
    #dark-light-container > div {
        float: left;
        box-sizing: border-box;
        position: relative;
        padding: 2rem;
        width: 50%;
        text-align: center;

    }
    .white-container { background: white; }
    .black-container { background: black; }

    button {
        box-shadow: none;
        background: transparent;
      font-family: Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;
        transform-style: preserve-3d;
        padding: 0;
        height: auto;
        float: none;
        appearance: none;
        border: none;
        letter-spacing: 1px;
    }

    button span {
        background: linear-gradient(180deg, #ff7147, #e0417f);
        font-size: 2rem;
        color: white;
        padding: 1rem 2rem;
        line-height: 3rem;
        will-change: transform, filter;
        float: none;
        margin: 0;
        transition: all 0.15s ease-out;
        height: auto;
        border-radius: 100px;
        overflow: hidden;
        display: block;
        margin: 0px auto;
        display: block;
        transform: rotateX(0deg) rotateY(0deg) scale(1);
        filter: drop-shadow(0 15px 15px rgba(0,0,0,0.3));
        font-weight: 500;
        perspective-origin: 0 0;
        letter-spacing: 0;
    }

    button.animated span:after {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 600%;
        height: 200%;
        background: linear-gradient(90deg, #00a1ff, #af4ae6, #00a1ff, #2cefff);
        animation: colorCycle 8s infinite alternate;
        z-index: -1;

    }
    button.green span {
        background: linear-gradient(180deg, #47ff6f, #417ce0);
        filter: drop-shadow(0 15px 15px rgba(71, 255, 111, 0.4));
    }

    button.animated span {
        filter: drop-shadow(0 15px 15px #00a1ff57);
    }

    button.purple span {
        background: linear-gradient(180deg, #e347ff, #7b41e0);
    }

    button.animated.example span:after {
        width: 200%;
        height: 100%;
        animation: colorCycleExample 4s infinite alternate;
    }
    
    @keyframes colorCycle {
        0% {
            top: 0;
            left: 0;
            transform: scale(1);
        }
        50% {
            top: -50%;
            transform: scale(1.4);
        }
        100% {
            top: 0;
            left: -500%;
            transform: scale(1);
        }
    }

    @keyframes colorCycleExample {
        0% {
            top: 0;
            left: 0;
            transform: scale(1);
        }
        100% {
            top: 0;
            left: -100%;
            transform: scale(1);
        }
    }

    @media screen and (max-width: 1000px) {
        #dark-light-container > div {
            width: 100%;
        }
    }

    let calculateAngle = function(e, item, parent) {
        let dropShadowColor = `rgba(0, 0, 0, 0.3)`
        if(parent.getAttribute('data-filter-color') !== null) {
            dropShadowColor = parent.getAttribute('data-filter-color');
        }

        // Get the x position of the users mouse, relative to the button itself
        let x = Math.abs(item.getBoundingClientRect().x - e.clientX);
        // Get the y position relative to the button
        let y = Math.abs(item.getBoundingClientRect().y - e.clientY);

        // Calculate half the width and height
        let halfWidth  = item.getBoundingClientRect().width / 2;
        let halfHeight = item.getBoundingClientRect().height / 2;

        // Use this to create an angle. I have divided by 6 and 4 respectively so the effect looks good.
        // Changing these numbers will change the depth of the effect.
        let calcAngleX = (x - halfWidth) / 6;
        let calcAngleY = (y - halfHeight) / 4;

        // Set the items transform CSS property
        item.style.transform = `rotateY(${calcAngleX}deg) rotateX(${calcAngleY}deg) scale(1.15)`;
        
        // And set its container's perspective.
        parent.style.perspective = `${halfWidth * 2}px`
        item.style.perspective = `${halfWidth * 3}px`

        if(parent.getAttribute('data-custom-perspective') !== null) {
            parent.style.perspective = `${parent.getAttribute('data-custom-perspective')}`
        }

        // Reapply this to the shadow, with different dividers
        let calcShadowX = (x - halfWidth) / 3;
        let calcShadowY = (y - halfHeight) / 3;
        
        // Add a filter shadow - this is more performant to animate than a regular box shadow.
        item.style.filter = `drop-shadow(${-calcShadowX}px ${calcShadowY}px 15px ${dropShadowColor})`;
    }

    document.querySelectorAll('.button').forEach(function(item) {
        item.addEventListener('mouseenter', function(e) {
            calculateAngle(e, this.querySelector('span'), this);
        });

        item.addEventListener('mousemove', function(e) {
            calculateAngle(e, this.querySelector('span'), this);
        });

        item.addEventListener('mouseleave', function(e) {
            let dropShadowColor = `rgba(0, 0, 0, 0.3)`
            if(item.getAttribute('data-filter-color') !== null) {
                dropShadowColor = item.getAttribute('data-filter-color')
            }
            item.querySelector('span').style.transform = `rotateY(0deg) rotateX(0deg) scale(1)`;
            item.querySelector('span').style.filter = `drop-shadow(0 10px 15px ${dropShadowColor})`;
        });
    })

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.