Parallax Cards


I say this beautiful animated card design on X a few weeks ago and wanted to see if I could recreate it. The blurring effect is not quite right, and the paralax is much harder than it looks. Then again the original was made in framer, while mine was hand coded.

I cut out the foreground element from photos I found from the internet. The result is not perfect. So spending more time on the actual photos would have made a real difference.

Using two overalapping blurring backgrounds worked surprisingly well.

My result as video

Paralax cards

My result as components

Berlin
Fernseherturn, Berlin
Stockholm
City hall, Stockholm

My implementation

    <div class="berlin card">
        <span>Berlin</span>
        <img src="/images/paralax-berlin-2.png" class="foreground" />
        <div class="caption">
            <div class="caption-content">Fernseherturn, Berlin</div>
        </div>
    </div>
.card {
        border-radius: 25px;
        overflow: hidden;
    }

    .berlin {
        background-image: url("/images/paralax-berlin-1.jpg");
        background-color: transparent;
        background-position: 50% 0%;
        background-repeat: no-repeat;
        background-size: 370px 320px;
        color: #fff;
        height: 300px;
        position: relative;
        width: 350px;
    }

    .berlin span {
        position: absolute;
        top: 50%;
        left: 50%;
        font-weight: 900;
        text-transform: uppercase;
        font-size: 56px;
        transform: translate(-50%, -50%);
    }

    .berlin img {
        height: 300px;
        left:50%;
        position: absolute;
        top:50%;
        transform: translate(-50%, -50%);
    }

    .caption {
        background-color: rgba(0,0,0,0.1);
        backdrop-filter: blur(1px);
        bottom: 0;
        font-size: 12px;
        font-weight: 600;
        left: 0;
        letter-spacing: 1px;
        padding: 1rem 0;
        position: absolute;
        right: 0;
        text-align: center;
        text-transform: uppercase;
        -webkit-backdrop-filter: blur(1px);
    }

    .caption-content {
        background-color: rgba(0,0,0,0.1);
        backdrop-filter: blur(2px);
        display: inline-block;
        padding: 0.5rem 0;
        -webkit-backdrop-filter: blur(2px);
    }
    const container = document.querySelector('.container');
    const berlin = document.querySelector('.berlin');
    const berlinText = document.querySelector('.berlin span');
    const berlinImg = document.querySelector('.berlin img');
    
    container.addEventListener("mousemove", (e) => {
        const containerX = window.innerWidth / 2;
        const containerY = window.innerHeight / 2;

        const xOffset = e.clientX - containerX;
        const yOffset = e.clientY - containerY;
        
        berlin.style['background-position'] = `${50 - xOffset * 0.02}% 50%`
        berlinText.style.left = `${50 - xOffset * 0.02}%`;
        berlinText.style.top = `${50 - yOffset * 0.01}%`;
        berlinImg.style.left = `${50 - xOffset * 0.0005}%`;
        berlinImg.style.top = `${50 - yOffset * 0.0005}%`;

    });

Categorydesign