Vissza az animációkhoz
Kártyaanimációk

Folyékony átalakulás

Élő előnézet – az animáció teljes méretben.

Élő előnézet
HTML · CSS · JS
HTML
<div class="we-card-morph">

    <div class="we-card-morph-shape"></div>

    <div class="we-card-morph-content">

        <span class="we-card-morph-label">
            04 / FÖLDÜNK CSODÁI
        </span>

        <h3>Vándorló erdők</h3>

        <p>
            Egy különleges természeti jelenség,
            ahol maga az erdő is mozgásban van.
        </p>

        <span class="we-card-morph-arrow">
            Felfedezem <b>↗</b>
        </span>

    </div>

</div>
CSS
.we-card-morph {
    position: relative;
    width: min(100%, 420px);
    height: 300px;
    overflow: hidden;

    border-radius: 26px;

    background: #0b1210;

    border: 1px solid rgba(95, 189, 125, .22);

    box-shadow:
        0 20px 50px rgba(0, 0, 0, .35);

    cursor: pointer;

    isolation: isolate;
}

.we-card-morph-shape {
    position: absolute;

    width: 330px;
    height: 330px;

    top: -125px;
    right: -105px;

    border-radius: 48% 52% 63% 37% / 42% 38% 62% 58%;

    background:
        radial-gradient(
            circle at 40% 45%,
            rgba(122, 201, 142, .28),
            rgba(63, 159, 99, .12) 45%,
            transparent 72%
        );

    transform: scale(1);

    transition:
        width .95s cubic-bezier(.22, 1, .36, 1),
        height .95s cubic-bezier(.22, 1, .36, 1),
        top .95s cubic-bezier(.22, 1, .36, 1),
        right .95s cubic-bezier(.22, 1, .36, 1),
        border-radius .95s cubic-bezier(.22, 1, .36, 1),
        transform .95s cubic-bezier(.22, 1, .36, 1);

    z-index: -1;
}

.we-card-morph-content {
    position: relative;
    z-index: 2;

    height: 100%;

    display: flex;
    flex-direction: column;
    justify-content: flex-end;

    padding: 34px;

    transform: translateY(0);

    transition:
        transform .75s cubic-bezier(.22, 1, .36, 1);
}

.we-card-morph-label {
    margin-bottom: 10px;

    color: #7ac98e;

    font-family: Inter, system-ui, sans-serif;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .16em;
}

.we-card-morph h3 {
    margin: 0 0 10px;

    color: #f4f1e9;

    font-family: "Bodoni Moda", Georgia, serif;
    font-size: clamp(30px, 5vw, 42px);
    font-weight: 500;
    line-height: 1.05;
}

.we-card-morph p {
    max-width: 310px;

    margin: 0 0 21px;

    color: rgba(244, 241, 233, .67);

    font-family: Inter, system-ui, sans-serif;
    font-size: 14px;
    line-height: 1.65;
}

.we-card-morph-arrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;

    color: #f4f1e9;

    font-family: Inter, system-ui, sans-serif;
    font-size: 13px;
    font-weight: 600;

    transition:
        transform .65s cubic-bezier(.22, 1, .36, 1);
}

.we-card-morph-arrow b {
    color: #7ac98e;
    font-size: 18px;
    font-weight: 400;

    transition:
        transform .65s cubic-bezier(.22, 1, .36, 1);
}


/* HOVER */

.we-card-morph:hover .we-card-morph-shape {
    width: 600px;
    height: 520px;

    top: -85px;
    right: -75px;

    border-radius:
        63% 37% 28% 72% /
        34% 54% 46% 66%;

    transform: rotate(14deg) scale(1.05);
}

.we-card-morph:hover .we-card-morph-content {
    transform: translateY(-5px);
}

.we-card-morph:hover .we-card-morph-arrow {
    transform: translateX(8px);
}

.we-card-morph:hover .we-card-morph-arrow b {
    transform: translate(4px, -3px);
}
JavaScript
document.querySelectorAll(".we-card-morph").forEach(card => {

    const shape = card.querySelector(
        ".we-card-morph-shape"
    );

    card.addEventListener("mousemove", event => {

        const rect = card.getBoundingClientRect();

        const x =
            (event.clientX - rect.left) /
            rect.width;

        const y =
            (event.clientY - rect.top) /
            rect.height;

        const moveX = (x - 0.5) * 14;
        const moveY = (y - 0.5) * 10;

        shape.style.transform = `
            rotate(14deg)
            scale(1.05)
            translate(${moveX}px, ${moveY}px)
        `;
    });

    card.addEventListener("mouseleave", () => {

        shape.style.transform =
            "rotate(0deg) scale(1) translate(0, 0)";
    });

});