Vissza a webes elemekhez
Fejlécek

Hullámzó vonalak

Élő előnézet – a komponens teljes méretben.

Élő előnézet
HTML · CSS · JS
HTML
<section class="hero-wave-lines">

    <div class="wave-lines-bg">

        <svg viewBox="0 0 1600 800" preserveAspectRatio="none">

            <path class="wave-path wave-path-1"
                  d="M-100,520 C250,260 430,720 760,470 S1250,180 1700,400"/>

            <path class="wave-path wave-path-2"
                  d="M-100,610 C220,340 480,760 800,510 S1260,230 1700,470"/>

            <path class="wave-path wave-path-3"
                  d="M-100,430 C280,180 500,610 820,390 S1280,130 1700,330"/>

            <path class="wave-path wave-path-4"
                  d="M-100,690 C300,430 500,820 850,590 S1280,340 1700,530"/>

            <path class="wave-path wave-path-5"
                  d="M-100,350 C300,80 560,500 900,310 S1300,70 1700,270"/>

        </svg>

    </div>


    <div class="wave-lines-content">

        <div class="wave-lines-kicker">
            <span></span>
            <em class="wave-typing"></em>
            <span class="wave-cursor"></span>
        </div>

        <h1>
            <span>Ideas that</span>
            <strong>move.</strong>
        </h1>

        <p>
            Kreatív digitális megoldások,
            amelyek nem maradnak mozdulatlanok.
        </p>

        <a href="#" class="wave-lines-button">
            Megnézem
            <span>↗</span>
        </a>

    </div>


    <div class="wave-lines-number">
        07
    </div>

    <div class="wave-lines-label">
        MOTION / FORM / DIGITAL
    </div>

</section>
CSS
.hero-wave-lines {
    position: relative;
    width: 100%;
    min-height: 760px;
    overflow: hidden;
    isolation: isolate;

    background:
        radial-gradient(
            circle at 70% 45%,
            rgba(92,110,101,.18),
            transparent 32%
        ),
        #101412;

    color: #f2eee5;

    font-family: Arial, sans-serif;
}


.wave-lines-bg {
    position: absolute;
    inset: 0;

    z-index: -1;

    opacity: .7;
}


.wave-lines-bg svg {
    width: 120%;
    height: 100%;

    margin-left: -10%;

    overflow: visible;
}


.wave-path {
    fill: none;

    stroke: rgba(201,181,141,.23);

    stroke-width: 1.2;

    vector-effect: non-scaling-stroke;

    animation:
        waveDrift 12s ease-in-out infinite;
}


.wave-path-1 {
    stroke-width: 1.8;
    stroke: rgba(210,190,150,.48);
}


.wave-path-2 {
    animation-delay: -2s;
}


.wave-path-3 {
    stroke: rgba(255,255,255,.12);
    animation-delay: -4s;
}


.wave-path-4 {
    animation-delay: -6s;
}


.wave-path-5 {
    stroke: rgba(122,145,132,.25);
    animation-delay: -8s;
}


.wave-lines-content {
    position: relative;

    width: min(900px, 88%);

    margin-left: 11%;
    padding-top: 20px;

    z-index: 5;
}


.wave-lines-kicker {
    display: flex;
    align-items: center;

    gap: 10px;

    margin-bottom: 28px;

    color: #bcae92;

    font-size: 10px;

    letter-spacing: 5px;

    text-transform: uppercase;
}


.wave-lines-kicker span:first-child {
    width: 40px;
    height: 1px;

    background: #bcae92;
}


.wave-lines-kicker em {
    min-width: 155px;

    font-style: normal;
}


.wave-cursor {
    width: 1px;
    height: 13px;

    background: #d7c19a;

    animation: waveCursor .7s infinite;
}


.wave-lines-content h1 {
    margin: 0;

    font-family:
        Georgia,
        "Times New Roman",
        serif;

    font-size:
        clamp(70px, 10vw, 145px);

    line-height: .83;

    font-weight: 400;

    letter-spacing: -6px;
}


.wave-lines-content h1 span,
.wave-lines-content h1 strong {
    display: block;

    opacity: 0;

    animation:
        waveTitleIn 1s
        cubic-bezier(.16,1,.3,1)
        forwards;
}


.wave-lines-content h1 span {
    animation-delay: .2s;
}


.wave-lines-content h1 strong {
    color: #d3bb8b;

    font-weight: 400;

    font-style: italic;

    margin-left: 16%;

    animation-delay: .55s;
}


.wave-lines-content p {
    max-width: 430px;

    margin: 38px 0 0;

    color: #9a9f9b;

    font-size: 14px;

    line-height: 1.8;

    opacity: 0;

    animation:
        waveFadeUp .8s ease .9s forwards;
}


.wave-lines-button {
    display: inline-flex;
    align-items: center;

    gap: 20px;

    margin-top: 30px;

    padding: 15px 23px;

    border: 1px solid rgba(211,187,139,.45);

    color: #f3eee5;

    text-decoration: none;

    font-size: 10px;

    letter-spacing: 3px;

    text-transform: uppercase;

    opacity: 0;

    animation:
        waveFadeUp .8s ease 1.1s forwards;

    transition: .35s ease;
}


.wave-lines-button span {
    font-size: 18px;

    transition: .35s ease;
}


.wave-lines-button:hover {
    background: rgba(211,187,139,.1);

    border-color: #d3bb8b;

    transform: translateY(-3px);
}


.wave-lines-button:hover span {
    transform: translate(4px,-4px);
}


.wave-lines-number {
    position: absolute;

    left: 35px;
    bottom: 30px;

    color: rgba(255,255,255,.22);

    font-family: Georgia, serif;

    font-size: 18px;
}


.wave-lines-label {
    position: absolute;

    right: 35px;
    bottom: 33px;

    color: #5d625e;

    font-size: 8px;

    letter-spacing: 3px;
}


@keyframes waveDrift {

    0%,100% {
        transform:
            translate3d(0,0,0)
            scaleY(1);
    }

    50% {
        transform:
            translate3d(-35px,18px,0)
            scaleY(1.035);
    }

}


@keyframes waveTitleIn {

    from {
        opacity: 0;

        transform:
            translateY(80px);

        filter: blur(8px);
    }

    to {
        opacity: 1;

        transform:
            translateY(0);

        filter: blur(0);
    }

}


@keyframes waveFadeUp {

    from {
        opacity: 0;

        transform:
            translateY(20px);
    }

    to {
        opacity: 1;

        transform:
            translateY(0);
    }

}


@keyframes waveCursor {

    0%,45% {
        opacity: 1;
    }

    46%,100% {
        opacity: 0;
    }

}


@media (max-width: 650px) {

    .hero-wave-lines {
        min-height: 680px;
    }

    .wave-lines-content {
        margin-left: 7%;
    }

    .wave-lines-content h1 {
        font-size: 17vw;

        letter-spacing: -3px;
    }

    .wave-lines-content h1 strong {
        margin-left: 8%;
    }

    .wave-lines-label {
        display: none;
    }

}


@media (prefers-reduced-motion: reduce) {

    .wave-path,
    .wave-lines-content h1 span,
    .wave-lines-content h1 strong,
    .wave-lines-content p,
    .wave-lines-button {
        animation: none !important;
        opacity: 1;
    }

}
JavaScript
document.addEventListener("DOMContentLoaded", () => {

    const hero =
        document.querySelector(".hero-wave-lines");

    if (!hero) return;


    const typing =
        hero.querySelector(".wave-typing");


    const words = [
        "Creative motion",
        "Fluid thinking",
        "Moving ideas",
        "Visual stories"
    ];


    let word = 0;
    let index = 0;
    let deleting = false;


    function type() {

        const current = words[word];

        if (!deleting) {

            index++;

            typing.textContent =
                current.substring(0, index);

            if (index === current.length) {

                deleting = true;

                setTimeout(type, 1600);

                return;
            }

            setTimeout(type, 70);

        } else {

            index--;

            typing.textContent =
                current.substring(0, index);

            if (index === 0) {

                deleting = false;

                word =
                    (word + 1) % words.length;

                setTimeout(type, 350);

                return;
            }

            setTimeout(type, 35);
        }
    }


    setTimeout(type, 700);


    if (
        window.matchMedia("(pointer:fine)").matches
    ) {

        hero.addEventListener(
            "mousemove",
            e => {

                const r =
                    hero.getBoundingClientRect();

                const x =
                    (e.clientX-r.left) /
                    r.width - .5;

                const y =
                    (e.clientY-r.top) /
                    r.height - .5;


                const content =
                    hero.querySelector(
                        ".wave-lines-content"
                    );


                if (content) {

                    content.style.transform =
                        `translate(${x*9}px,${y*6}px)`;
                }

            }
        );

    }

});