Vissza az animációkhoz
Háttéranimációk

Élő topográfiai vonalak

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

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

    <svg class="we-bg-topographic-svg"
         viewBox="0 0 1200 700"
         preserveAspectRatio="none"
         aria-hidden="true">

        <g class="we-topo-lines">

            <path d="M-100 120
                     C120 20 260 210 470 115
                     S820 40 1300 145" />

            <path d="M-120 175
                     C100 75 280 270 500 165
                     S850 90 1320 195" />

            <path d="M-130 235
                     C90 125 300 335 530 225
                     S900 140 1340 250" />

            <path d="M-140 300
                     C80 185 315 400 555 290
                     S930 200 1350 310" />

            <path d="M-150 370
                     C70 245 330 470 580 355
                     S960 270 1360 375" />

            <path d="M-160 445
                     C60 315 345 545 605 430
                     S990 340 1370 450" />

            <path d="M-170 525
                     C45 390 360 625 630 510
                     S1020 420 1380 530" />

            <path d="M-180 610
                     C30 475 375 710 650 595
                     S1040 500 1390 615" />

        </g>

    </svg>

    <div class="we-bg-topographic-content">
        <span>WEBELEMENTS</span>
        <h2>Élő domborzat</h2>
        <p>
            A háttér szintvonalai lassan változnak,
            mintha egy folyamatosan mozgó térképet látnál.
        </p>
    </div>

</div>
CSS
.we-bg-topographic {
    position: relative;

    width: 100%;
    min-height: 420px;

    overflow: hidden;

    background: #080b11;

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

    isolation: isolate;
}

.we-bg-topographic-svg {
    position: absolute;

    inset: -8% -6%;

    width: 112%;
    height: 116%;

    overflow: visible;

    opacity: .5;

    transform: rotate(-3deg) scale(1.04);

    pointer-events: none;
}

.we-topo-lines {
    fill: none;

    stroke: #3f9f63;

    stroke-width: 1.2;

    stroke-linecap: round;

    stroke-dasharray: 900 80;

    animation:
        weTopoFlow 18s linear infinite,
        weTopoMorph 11s ease-in-out infinite alternate;
}

.we-topo-lines path:nth-child(2) {
    opacity: .82;
    animation-delay: -2s, -1s;
}

.we-topo-lines path:nth-child(3) {
    opacity: .7;
    animation-delay: -4s, -2s;
}

.we-topo-lines path:nth-child(4) {
    opacity: .62;
    animation-delay: -6s, -3s;
}

.we-topo-lines path:nth-child(5) {
    opacity: .55;
    animation-delay: -8s, -4s;
}

.we-topo-lines path:nth-child(6) {
    opacity: .48;
    animation-delay: -10s, -5s;
}

.we-topo-lines path:nth-child(7) {
    opacity: .4;
    animation-delay: -12s, -6s;
}

.we-topo-lines path:nth-child(8) {
    opacity: .32;
    animation-delay: -14s, -7s;
}

@keyframes weTopoFlow {

    from {
        stroke-dashoffset: 0;
    }

    to {
        stroke-dashoffset: -980;
    }

}

@keyframes weTopoMorph {

    0% {
        transform: translate3d(-8px, 0, 0);
    }

    50% {
        transform: translate3d(8px, -5px, 0);
    }

    100% {
        transform: translate3d(-4px, 7px, 0);
    }

}

.we-bg-topographic-content {
    position: relative;

    z-index: 2;

    max-width: 650px;

    padding: 48px;

    text-align: center;

    color: #f4f1e9;

    pointer-events: none;
}

.we-bg-topographic-content span {
    display: block;

    margin-bottom: 16px;

    color: #7ac98e;

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

    font-size: 10px;
    font-weight: 700;

    letter-spacing: .2em;
}

.we-bg-topographic-content h2 {
    margin: 0 0 14px;

    font-family: "Bodoni Moda", Georgia, serif;

    font-size: clamp(40px, 7vw, 72px);

    font-weight: 500;

    line-height: 1;
}

.we-bg-topographic-content p {
    margin: 0;

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

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

    font-size: 14px;

    line-height: 1.7;
}
JavaScript
document.querySelectorAll(".we-bg-topographic").forEach(background => {

    const svg = background.querySelector(
        ".we-bg-topographic-svg"
    );

    let targetX = 0;
    let targetY = 0;

    let currentX = 0;
    let currentY = 0;

    function animate() {

        currentX +=
            (targetX - currentX) * .035;

        currentY +=
            (targetY - currentY) * .035;

        svg.style.transform =
            `rotate(-3deg) scale(1.04)
             translate3d(${currentX}px, ${currentY}px, 0)`;

        requestAnimationFrame(animate);
    }

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

        const rect =
            background.getBoundingClientRect();

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

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

        targetX =
            (x - .5) * 28;

        targetY =
            (y - .5) * 18;
    });

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

        targetX = 0;
        targetY = 0;

    });

    animate();

});