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

Kihúzható idővonal

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

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

    <div class="we-card-timeline-main">
        <span class="we-card-timeline-number">07</span>

        <h3>Időrétegek</h3>

        <p>
            Egy pillanat, amely mögött évszázadok története rejtőzik.
        </p>
    </div>

    <div class="we-card-timeline-track">

        <div class="we-card-timeline-line"></div>

        <div class="we-card-timeline-item">
            <span>01</span>
            <strong>KEZDET</strong>
        </div>

        <div class="we-card-timeline-item">
            <span>02</span>
            <strong>NYOM</strong>
        </div>

        <div class="we-card-timeline-item">
            <span>03</span>
            <strong>FELFEDEZÉS</strong>
        </div>

    </div>

</div>
CSS
.we-card-timeline {
    position: relative;

    width: min(100%, 420px);
    height: 300px;

    overflow: hidden;

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

    background: #173b2b;

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

    cursor: pointer;
}

.we-card-timeline-main {
    position: relative;
    z-index: 2;

    height: 100%;

    padding: 34px;

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

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

.we-card-timeline-number {
    margin-bottom: 16px;

    color: #7ac98e;

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

.we-card-timeline h3 {
    margin: 0 0 14px;

    color: #f4f1e9;

    font-family: "Bodoni Moda", Georgia, serif;
    font-size: clamp(32px, 5vw, 46px);
    font-weight: 500;
    line-height: 1;
}

.we-card-timeline p {
    max-width: 290px;

    margin: 0;

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

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


/* Kihúzódó idővonal */

.we-card-timeline-track {
    position: absolute;

    left: 0;
    bottom: 0;

    width: 100%;
    height: 76px;

    padding: 0 28px;

    display: flex;
    align-items: center;
    justify-content: space-between;

    background: #0b1210;

    transform: translateY(100%);

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

    z-index: 3;
}

.we-card-timeline-line {
    position: absolute;

    left: 42px;
    right: 42px;
    top: 37px;

    height: 1px;

    background: rgba(122, 201, 142, .28);

    transform: scaleX(0);
    transform-origin: left;

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

.we-card-timeline-item {
    position: relative;

    display: flex;
    flex-direction: column;
    gap: 5px;

    color: #f4f1e9;

    font-family: Inter, system-ui, sans-serif;

    opacity: 0;
    transform: translateY(12px);

    transition:
        opacity .45s ease,
        transform .6s cubic-bezier(.22, 1, .36, 1);
}

.we-card-timeline-item span {
    color: #7ac98e;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .12em;
}

.we-card-timeline-item strong {
    font-size: 9px;
    font-weight: 600;
    letter-spacing: .08em;
}


/* Hover */

.we-card-timeline:hover .we-card-timeline-main {
    transform: translateY(-24px);
}

.we-card-timeline:hover .we-card-timeline-track {
    transform: translateY(0);
}

.we-card-timeline:hover .we-card-timeline-line {
    transform: scaleX(1);
}

.we-card-timeline:hover .we-card-timeline-item {
    opacity: 1;
    transform: translateY(0);
}

.we-card-timeline:hover .we-card-timeline-item:nth-child(2) {
    transition-delay: .28s;
}

.we-card-timeline:hover .we-card-timeline-item:nth-child(3) {
    transition-delay: .38s;
}

.we-card-timeline:hover .we-card-timeline-item:nth-child(4) {
    transition-delay: .48s;
}
JavaScript
document.querySelectorAll(".we-card-timeline").forEach(card => {

    const track = card.querySelector(".we-card-timeline-track");

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

        const rect = card.getBoundingClientRect();

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

        const offset = (x - 0.5) * 8;

        track.style.transform =
            `translateY(0) translateX(${offset}px)`;
    });

    card.addEventListener("mouseleave", () => {
        track.style.transform = "";
    });

});