如何在保持固定状态后将元素设置回相对位置

问题描述 投票:0回答:1

https://codepen.io/BlazgoCompany/pen/dyBBRLp

我正在尝试制作一个带有大量滚动动画的网站(文本已被屏蔽)。第一个带有放大星星的动画效果很好,但第二个动画不起作用。它像平常一样播放动画,但是一旦完成,它就不会返回到常规滚动。动画完成后,它还应该继续其下方的文本。

我很确定我需要将其设置为相对但似乎无法让它工作。

另外,请不要建议使用

ScrollTrigger
,因为它不会永远保留在 CodePen 上,而且我不想获得 Club GSAP。

由于某种原因我无法使用堆栈片段,所以这里是完整的代码:

<div class="top-right">
    <span class="cta-login">
        <button class="my-dash btn-base">Lorem Ipsum</button>
    </span>
</div>
<div class="nav">
    <span class="logo">
        <!-- Logo Placeholder -->
    </span>
    <span class="cta-login">
        <button class="login btn-base" onclick="openModal()">Login</button>
    </span>
</div>
<div class="hero">
    <h1 class="hero-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h1>
</div>
<div class="content">
    <small class="subtitle">Sed do eiusmod tempor incididunt.</small>
    <h2 style="margin-bottom: 0">
        <span class="brand gradient teal text">Lorem.</span>
        <span class="brand gradient blue text">Ipsum.</span>
    </h2>
    <h2 class="brand gradient red text">Dolor Sit Amet.</h2>
    <p style="color: #999">Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <span class="highlight">Ut enim</span> ad minim veniam, quis nostrud <span class="highlight">exercitation</span> ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    <button class="getstarted">Get Started</button>
    <div class="spacer-240"></div>
    <h1 class="tw-heading gray">Placeholder Heading</h1>
    <div class="gen-card">
        <h2>Placeholder Title</h2>
        <h4>Placeholder Subtitle</h4>
        <p>Placeholder text for description.</p>
    </div>
    <div class="gen-card">
        <h2>Placeholder Title</h2>
        <h4>Placeholder Subtitle</h4>
        <p>Placeholder text for description.</p>
    </div>
    <div class="gen-card">
        <h2>Placeholder Title</h2>
        <h4>Placeholder Subtitle</h4>
        <p>Placeholder text for description.</p>
    </div>
    <div class="gen-card">
        <h2>Placeholder Title</h2>
        <h4 class="anim brand red text">Placeholder Subtitle</h4>
        <p>Placeholder text for description.</p>
    </div>
    This text should appear after this scroll animation (but it doesn't!)
</div>

@import url('https://fonts.googleapis.com/css?family=Nunito:200,200i');
    @import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500');
    @import url('https://fonts.googleapis.com/css?family=Varela+Round');

    /* Import fonts */
    /* Global Styles */
    body {
        background: black;
        overflow-x: hidden;
        min-height: 800vh;
        margin: 0;
        font-family: sans-serif;
        /* Fallback font */
    }

    input {
        padding: 12px;
        width: 80%;
        border-radius: 8px;
        border: none;
        left: 50%;
        position: relative;
        transform: translate(-50%);
        margin-top: 42px;
    }

    .hero {
        padding: 16px;
        position: fixed;
        width: 100%;
        height: 100vh;
        background: radial-gradient(circle at 0% -10%, var(--gradient-color), transparent 38%);
    }

    .hero-text {
        color: white !important;
        font-size: 64px;
        font-family: "Varela Round", sans-serif;
        /* Default to Varela Round, fallback to sans-serif */
        display: inline-block;
        position: relative;
        z-index: 10;
    }

    .hero-text svg {
        transform: translateY(-4px);
        display: inline;
        vertical-align: middle;
        background-color: transparent;
    }

    .content {
        color: white;
        display: none;
        font-family: "Varela Round";
        text-align: center;
    }

    .highlight {
        color: #e3b505;
    }

    .btn-base,
    .modal .login,
    .backbtn {
        border-radius: 20px;
        border: none;
        padding: 0 12px;
        height: 30px;
        background: #e3b505;
        font-size: 16px;
        font-weight: bold;
    }

    .btn-base:hover,
    .modal .login:hover,
    .backbtn:hover {
        background: #c8a104;
    }

    .getstarted {
        padding: 8px 16px;
        border-radius: 32px;
        height: auto;
    }

    .nav {
        position: fixed;
        top: -36px;
        background: radial-gradient(circle at 0% center, #066ab2, transparent 80%);
        backdrop-filter: blur(8px);
        width: calc(100% - 32px);
        height: 36px;
        z-index: 1000;
        left: 50%;
        transform: translate(-50%, 0);
        max-width: 500px;
        border-radius: 32px;
    }

    button:active {
        transform: scale(0.9)
    }

    button {
        transition: transform 0.1s;
    }


    .btncontainer {
        margin-top: 48px;
        left: 50%;
        position: relative;
        transform: translate(-50%);
        display: inline-block;
    }

    .btn-close {
        position: absolute;
        right: 8px;
        top: 8px;
        width: 32px;
        height: 32px;
        background: #95190C;
        color: white
    }

    .btn-close:hover {
        background: #711409;
    }

    .loader {
        height: 24px;
        width: 24px;
        border: 3px solid transparent;
        border-bottom: 3px solid black;
        border-radius: 32px;
        animation: spin 1s linear infinite;
    }

    @keyframes spin {
        0% {
            transform: rotate(0deg);
        }

        100% {
            transform: rotate(360deg);
        }

    }

    .login-modal h1 {
        font-size: 24px;
        font-weight: bold;
        text-align: center;
        margin-bottom: -20
    }

    .brand.gradient.teal.text {
        background: #107E7D;
        background: -webkit-linear-gradient(#28E2DF, #0C5A59);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .brand.gradient.blue.text {
        background: #066AB1;
        background: -webkit-linear-gradient(#89CBFB, #05528A);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .brand.gradient.blue.extra {
        background: #066AB1;
        background: -webkit-linear-gradient(#C4E5FD, #05528A);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .brand.gradient.red.text {
        margin-top: 0;
        background: #971A0C;
        background: -webkit-linear-gradient(#F6877B, #711409);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    h2 {
        font-size: 32px;
    }

    .subtitle {
        font-size: 14px;
        background: -webkit-linear-gradient(#eee, #3f3f3f);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .subtitle::after,
    .subtitle::before {
        content: '';
        width: 64px;
        height: 1px;
        display: inline-block;
    }

    .subtitle::before {

        transform: translate(-8px, -4px);
        background: linear-gradient(-90deg, #aaa 0%, transparent 100%);
        right: 120%;
        top: 50%;
    }

    .subtitle::after {
        transform: translate(8px, -4px);
        background: linear-gradient(90deg, #aaa 0%, transparent 100%);
        left: 120%;
        top: 50%;
    }

    h1.gray.tw-heading {
        font-size: 48px;
        background: -webkit-linear-gradient(#eee, #333);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .spacer-240 {
        height: 240px;
    }

    .gen-card {
        width: calc(25% - 14px);
        margin: 0 4px;
        display: inline-block;
        height: 360;
        background: transparent;
        backdrop-filter: blur(4px);
        opacity: 0;
        border-radius: 16px;
        text-align: center;
        padding: 12px;
        border: 1px solid #555
    }

    .gen-card h2 {
        margin: 0;
    }

    .fixed {
        position: fixed;
    }
    .relative{
        position: relative;
    }

    /* .anim.brand.red.text{
        margin-top: 0;
        background: #971A0C;
        background: -webkit-linear-gradient(#F6877B, #711409);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    } */

    function setTransformOriginToChild() {
        const parent = document.querySelector('.hero-text');
        const child = document.querySelector('.hero-text .star');

        const parentRect = parent.getBoundingClientRect();
        const childRect = child.getBoundingClientRect();

        const childCenterX = (childRect.left - 10 + childRect.right) / 2;
        const childCenterY = (childRect.top + 4 + childRect.bottom) / 2;

        const transformOriginX = (childCenterX - parentRect.left) / parentRect.width * 100;
        const transformOriginY = (childCenterY - parentRect.top) / parentRect.height * 100;

        parent.style.transformOrigin = `${transformOriginX}% ${transformOriginY}%`;
    }



    window.addEventListener('resize', setTransformOriginToChild);


    
    // Function to split text into multiple spans
    function splitTextIntoSpans() {
        // Get the container element
        const container = document.querySelector('.hero-text');

        // Get the text content of the container
        const text = container.textContent;

        // Create a document fragment to hold the new span elements
        const fragment = document.createDocumentFragment();

        // Define words to style
        const wordsToStyle = {
            'future': '#066AB2',
            'sit': '#066AB2'
        };

        // Helper function to create span elements for text
        function createSpansForText(text, color = '') {
            const fragment = document.createDocumentFragment();
            for (let char of text) {
                const span = document.createElement('span');
                span.textContent = char;
                if (color) {
                    span.classList.add("brand")
                    span.classList.add("gradient")
                    span.classList.add("blue")
                    span.classList.add("text")
                    span.classList.add("extra")
                }
                fragment.appendChild(span);
            }
            return fragment;
        }

        // Process the text letter by letter
        let index = 0;
        while (index < text.length) {
            // Find the next word or space
            let nextSpace = text.indexOf(' ', index);
            if (nextSpace === -1) {
                nextSpace = text.length;
            }

            var word = text.slice(index, nextSpace);

            // Add a space character after the word
            if (nextSpace < text.length) {
                word += ' ';
            }

            // Create spans for each letter of the word
            const color = wordsToStyle[word.trim()] || '';
            const wordFragment = createSpansForText(word, color);
            fragment.appendChild(wordFragment);

            // If the word  add a special span element after it
            if (word.trim() === 'sit') {
                const starSpan = document.createElement('span');
                starSpan.className = 'star';
                starSpan.innerHTML = `
      <svg width="32" height="24">
        <path d="M 2 12 q 10 0 10 -10 q 0 10 10 10 q -10 0 -10 10 q 0 -10 -10 -10 M 0 12 A 1 1 0 0 0 24 12 A 1 1 0 0 0 0 12"></path>
      </svg>`;
                fragment.appendChild(starSpan);
            }

            // Move to the next word
            index = nextSpace + 1;
        }

        // Clear the original container
        container.textContent = '';

        // Append the fragment to the container
        container.appendChild(fragment);
    }
    function calculateTravelDistance() {
        // Get the .star element
        const starElement = document.querySelector('.hero-text .star');

        // Get the bounding rectangle of the .star element
        const starRect = starElement.getBoundingClientRect();

        // Get the center of the .star element
        const starCenterX = starRect.left + starRect.width / 2;
        const starCenterY = starRect.top + starRect.height / 2;

        // Get the center of the screen
        const screenCenterX = window.innerWidth / 2;
        const screenCenterY = window.innerHeight / 2;

        // Calculate the amount to move the element
        const moveX = screenCenterX - starCenterX;
        const moveY = screenCenterY - starCenterY;

        return { moveX, moveY };
    }
    // Call the function to split the text
    window.addEventListener('load', () => {
        splitTextIntoSpans();
        setTransformOriginToChild()
        tl = gsap.timeline({
        })
        tl.set(".hero-text span", { filter: "blur(32px)" })
        tl.set(".hero", { "--gradient-color": "#FFD700" })
        tl.set(".hero-text svg", { fill: "white" })
        tl.to(".hero-text span", { filter: "blur(0px)", duration: 0.5, stagger: 0.05 })
        tl.to(".top-right", { opacity: 0, duration: 0.8 }, "<+=1.2")
        tl.to(".hero-text", { y: calculateTravelDistance().moveY, x: calculateTravelDistance().moveX, duration: 3, fill: "black", ease: "power4.in" }, "+=0.5")
        tl.to(".hero-text", { scale: 90, duration: 3, ease: "power4.in" }, "<")
        tl.to(".hero-text svg", { duration: 1, fill: "black", background: "transparent" }, "-=1")
        tl.to(".hero", { duration: 1, "--gradient-color": "#000" }, "-=1")
        tl.to(".nav", { duration: 1, top: "16px" }, "-=1")
        tl.pause(0.5)
    });
    var gentlmarker = 1000000
    var gentl = 0
    document.addEventListener("scroll", () => {
        //get scroll position
        const scrollPosition = window.scrollY;
        if ((scrollPosition / 200) + 0.5 < 5.8) {
            gsap.set(".hero", { display: "block" })
            gsap.set(".content", { display: "none" })
            tl.pause((scrollPosition / 200) + 0.5)
        }
        else {
            gsap.set(".hero", { display: "block" })
            gsap.set(".content", { display: "none" })
            tl.pause((scrollPosition / 200) + 0.5)
            gsap.set(".hero", { display: "none" })
            gsap.set(".content", { position: "relative", top: 1060 + window.innerHeight, display: "block" })
        }
        if(document.querySelector(".tw-heading").getBoundingClientRect().top < 200 && scrollPosition > 1800){
            //"pin" the tw-heading and the gencards for 300 px of scrolling
            gsap.set(".tw-heading", {position: "fixed", top: 200-32, left: "50%", xPercent: -50, width: "100%"})
            gc = document.querySelectorAll(".gen-card")
            gcw = gc[0].getBoundingClientRect().width
            gsap.set(".gen-card", {position: "fixed", opacity: 1, top: 264, right: -gcw})
            gentl=gsap.timeline({})
            // gentl.to(gc[0], {position: "fixed", top: 264, left: 8})
            // gentl.to(gc[1], {position: "fixed", top: 264, left: 8+gcw+8})
            // gentl.to(gc[2], {position: "fixed", top: 264, left: 8+gcw+8+gcw+8})
            // gentl.to(gc[3], {position: "fixed", top: 264, left: 8+gcw+8+gcw+8+gcw+8})
            

            // Common properties for the animation
            const commonProps = {
                position: "fixed",
                top: 264
            };

            // Define the start position and end positions for gc elements
            const startPosition = -200;
            const endPositionFirst = -gcw;
            const endPositionLast = 32;

            // Create a timeline animation with stagger
            gentl.to(gc, {
                ...commonProps,
                left: endPositionFirst,
                stagger: 0.2, // Stagger by 0.1 seconds for each element
                duration: 1,  // Adjust duration to your preference
                ease: "power1.inOut" // Example easing function
            })
            .to(gc[gc.length - 1], {
                left: endPositionLast,
                duration: 1, // Same duration as above to keep consistency
                ease: "power1.inOut" // Use the same easing function
            }, "-=1")
            .to(gc[3], {
                width: "50%",
                left: "50%",
                x: "-50%",
                duration: 1, // Same duration as above to keep consistency
                ease: "power1.inOut" 
            })
            .addLabel("fgenfocus")
            .to(gc[3].querySelector("h2"), {
                opacity: 0
            }, "fgenfocus")
            .to(gc[3].querySelector("h2"), {
                opacity: 0,
                height: "0px",
                margin: 0
            }, "fgenfocus")
            .add(function(){
              gc[3].querySelector("h4").innerHTML="Now the th scrolling should continue as normal"
            }, "fgenfocus")
            .to(gc[3].querySelector("h4"), {
                fontSize: "32px",
                margin: 0
            }, "fgenfocus")


            // gentl.to([gc[0], gc[1], gc[2]], {width: 0})
            gentl.pause()
            gentlmarker = scrollPosition
            

        }
        if(scrollPosition>gentlmarker){
            gc = document.querySelectorAll(".gen-card")
            gcw = gc[0].getBoundingClientRect().width
            
            console.log(gentlmarker)
            console.log((scrollPosition-gentlmarker)/300)
            console.log("----------------")
            gentl.pause((scrollPosition-gentlmarker)/300)
        }

        if((scrollPosition-gentlmarker)/300 < 0){
            gsap.set(".tw-heading", {position: "static", xPercent: 0})
            gsap.set(".gen-card", { opacity: 0 })
        }
       

    })




    







    document.querySelector(".getstarted").addEventListener("click", () => {
        let clickTl = gsap.timeline({})
        clickTl.to(".getstarted", { scale: 100, duration: 2, ease: "power4.in" })
        clickTl.to(".getstarted", { background: "black", color: "black", duration: 1, ease: "power4.in" }, "-=1")
    })

谢谢!

javascript css animation scroll gsap
1个回答
0
投票

确保您的动画完成,并且

.gen-card
完成后重置。

使用这个Javascript:

document.addEventListener("scroll", () => {
    const scrollPosition = window.scrollY;

    if (scrollPosition / 200 + 0.5 < 5.8) {
        gsap.set(".hero", { display: "block" });
        gsap.set(".content", { display: "none" });
        tl.pause(scrollPosition / 200 + 0.5);
    } else {
        gsap.set(".hero", { display: "none" });
        gsap.set(".content", { display: "block", top: 1060 + window.innerHeight });
    }

    const twHeadingTop = document.querySelector(".tw-heading").getBoundingClientRect().top;

    // Trigger the second animation
    if (twHeadingTop < 200 && scrollPosition > 1800) {
        gsap.set(".tw-heading", {
            position: "fixed",
            top: 200 - 32,
            left: "50%",
            xPercent: -50,
        });

        const gc = document.querySelectorAll(".gen-card");
        const gcw = gc[0].getBoundingClientRect().width;

        gsap.set(gc, {
            position: "fixed",
            opacity: 1,
            top: 264,
            right: -gcw,
        });

        gentl = gsap.timeline({})
            .to(gc, {
                position: "fixed",
                top: 264,
                left: -gcw,
                stagger: 0.2,
                duration: 1,
                ease: "power1.inOut",
            })
            .to(gc[gc.length - 1], {
                left: 32,
                duration: 1,
                ease: "power1.inOut",
            }, "-=1")
            .to(gc[3], {
                width: "50%",
                left: "50%",
                x: "-50%",
                duration: 1,
                ease: "power1.inOut",
            })
            .addLabel("fgenfocus")
            .to(gc[3].querySelector("h2"), {
                opacity: 0,
            }, "fgenfocus")
            .to(gc[3].querySelector("h2"), {
                opacity: 0,
                height: "0px",
                margin: 0,
            }, "fgenfocus")
            .add(() => {
                gc[3].querySelector("h4").innerHTML = "Now the scrolling should continue as normal";
            }, "fgenfocus")
            .to(gc[3].querySelector("h4"), {
                fontSize: "32px",
                margin: 0,
            }, "fgenfocus");

        gentl.pause();
        gentlmarker = scrollPosition;
    }

    if (scrollPosition > gentlmarker) {
        const gc = document.querySelectorAll(".gen-card");
        gcw = gc[0].getBoundingClientRect().width;

        gentl.pause((scrollPosition - gentlmarker) / 300);
    }

    if ((scrollPosition - gentlmarker) / 300 < 0) {
        gsap.set(".tw-heading", { position: "static", xPercent: 0 });
        gsap.set(".gen-card", { position: "static", opacity: 1 });
    }

    if (scrollPosition > gentlmarker + 300) {
        gsap.set(".tw-heading", { position: "relative" });
        gsap.set(".gen-card", { position: "relative", top: "auto" });
    }
});
© www.soinside.com 2019 - 2024. All rights reserved.