Jump to content
Search Community

There's extra space below the section even though i have given the section a fixed height of 680px

Sid1509

Go to solution Solved by Rodrigo,

Recommended Posts

Posted (edited)

image.thumb.png.1823e38023998b33159f6e02b72c80af.png

There's this extra space below the section even though i have given the section 680px of height..
and also at the end of this sectiona massive space is coming even though i never added it?..
image.thumb.png.33bd5dfb4c7e143af7f18f736f6b16e3.png

 

 

heres the code

 

 

"use client"
import React, { useEffect, useRef } from 'react'
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger'
 
const steps = [
  {
    id: 1,
    number: '1',
    title: 'Initial Discovery & Research',
    desc: 'We begin by aligning your goals with market research to validate and shape ideas.'
  },
  {
    id: 2,
    number: '2',
    title: 'Brainstorming & Idea Generation',
    desc: 'We collaborate through brainstorming to spark innovation and explore diverse ideas.'
  },
  {
    id: 3,
    number: '3',
    title: 'Idea Screening & Selection',
    desc: 'We filter ideas by feasibility, goals, and market fit to focus on those with the highest potential.'
  },
  {
    id: 4,
    number: '4',
    title: 'User Persona Development',
    desc: 'We craft user personas to tailor concepts around real needs, behaviours, and pain points for user-centric solutions.'
  },
  {
    id: 5,
    number: '5',
    title: 'Feasibility Study & Risk Assessment',
    desc: 'We assess feasibility and risks to build a strong, strategic foundation for product development.'
  },
  {
    id: 6,
    number: '6',
    title: 'Prototyping & Concept Visualization',
    desc: 'We create prototypes and wireframes to visualize ideas, refine concepts, and gather stakeholder feedback.'
  },
  {
    id: 7,
    number: '7',
    title: 'Feedback & Iteration',
    desc: 'We gather feedback to refine prototypes, ensuring concepts meet user needs and market expectations.'
  },
  {
    id: 8,
    number: '8',
    title: 'Defining the Product Roadmap',
    desc: 'We design a product roadmap that defines timelines, milestones, and goals to guide development.'
  },
  {
    id: 9,
    number: '9',
    title: 'Final Concept Approval',
    desc: 'The process ends with final concept approval, aligning all stakeholders for development.'
  }
]
 
function ProductSuccess() {
  const sectionRef = useRef<HTMLDivElement | null>(null)
  const cardsContainerRef = useRef<HTMLDivElement | null>(null)
  const cardRefs = useRef<Array<HTMLDivElement | null>>([])
 
  useEffect(() => {
    gsap.registerPlugin(ScrollTrigger)
    // Offset to leave space for fixed navbar (adjust if navbar height changes)
    const NAV_OFFSET_PX = -45
 
    const section = sectionRef.current
    const cardsContainer = cardsContainerRef.current
    const cards = cardRefs.current
 
    if (!section || !cardsContainer || cards.length === 0) return
 
    // Calculate card height + gap
    const cardHeight = cards[0]?.offsetHeight || 0
    const gap = 16 // mb-4 = 16px
    const totalCardHeight = cardHeight + gap
 
    // Set initial positions - all cards stacked below the viewport
    cards.forEach((card, index) => {
      if (index === 0) {
        gsap.set(card, { y: 0 })
      } else {
        // Position each card below the previous one
        gsap.set(card, { y: totalCardHeight * index })
      }
    })
 
    // Create timeline for the animation
    const tl = gsap.timeline({
      scrollTrigger: {
        trigger: section,
        // start when section hits just below navbar
        start: `top+=${NAV_OFFSET_PX} top`,
        end: () => `+=${totalCardHeight * (cards.length - 1) + window.innerHeight}`,
        scrub: 0.5,
        pin: true,
        anticipatePin: 1,
      }
    })
 
    // Animate each card group
    cards.forEach((card, index) => {
      if (index > 0) {
        // Move all cards from current index onwards up by one card height
        const cardsToMove = cards.slice(index)
       
        tl.to(cardsToMove, {
          y: (cardIndex) => {
            const originalIndex = index + cardIndex
            const newPosition = totalCardHeight * (originalIndex - index)
            return newPosition
          },
          duration: 1,
          ease: "none",
          stagger: 0
        }, index === 1 ? 0 : ">")
      }
    })
 
    return () => {
      ScrollTrigger.getAll().forEach(trigger => trigger.kill())
    }
  }, [])
 
  return (
    <section ref={sectionRef} className="w-full bg-white py-12 md:py-16 lg:py-20 h-[680px] overflow-hidden">
      <div className="max-w-7xl mx-auto px-4 lg:px-0">
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-12 items-start">
 
          {/* Left: Heading + paragraph (pinned) */}
          <div className="flex flex-col justify-start lg:sticky lg:top-0">
            <h2 className="font-['Inter'] font-semibold text-[28px] md:text-[32px] lg:text-[36px] leading-[120%] text-[#000000] max-w-[550px]">
              From Vision to Reality: Our Proven Path to Product Success
            </h2>
 
            <p className="mt-4 md:mt-8 font-['Inter'] font-normal text-[16px] leading-[24px] text-[#00000066] max-w-xl">
              Our product ideation and conceptualization is a step-by-step journey from brainstorming and research to prototyping and refinement. We then craft a strategic roadmap to guide your concept into development, ensuring every decision aligns with your vision.
            </p>
          </div>
 
          {/* Right: Steps list with animation */}
          <div className="w-full relative">
            <div ref={cardsContainerRef} className="relative h-[200px]">
              <div className="absolute top-0 left-0 w-full">
                {steps.map((s, index) => (
                  <div
                      key={s.id}
                      ref={el => { cardRefs.current[index] = el }}
                      className="absolute top-0 left-0 w-full"
                    >
                    <div className="flex items-stretch gap-[36px]">
                      {/* Strip */}
                      <div className="w-[66px] flex flex-col items-center flex-shrink-0 bg-white">
                        <div className="text-left whitespace-nowrap bg-white font-['Inter'] font-semibold text-[15px] leading-[20px] text-[#000000]">
                          {`STEP - 0${s.number}`}
                        </div>
                        <div className="flex-1 w-full flex items-start min-h-[120px]">
                          <div
                            className="mx-auto w-0.5 h-full"
                            style={{
                              background: 'repeating-linear-gradient(to bottom, #00000033 0px, #00000033 4px, transparent 4px, transparent 6px)'
                            }}
                          />
                        </div>
                      </div>
 
                      {/* Card */}
                      <div className="flex-1 mb-4">
                        <div className="bg-[#FAFAFA] rounded-[12px] p-6">
                          <div className="flex flex-col items-start">
                            <div className="w-[48px] h-[48px] rounded-[8px] bg-[#3C82F6] flex items-center justify-center mb-3">
                              <span className="font-['Inter'] font-bold text-[24px] leading-[24px] text-white">{s.number}</span>
                            </div>
 
                            <div className="font-['Inter'] font-medium text-[18px] leading-[27px] text-[#0C0C0C]">
                              {s.title}
                            </div>
                            <div className="mt-1 font-['Inter'] font-normal text-[12px] leading-[20px] text-[#00000066]">
                              {s.desc}
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          </div>
 
        </div>
      </div>
    </section>
  )
}
 
export default ProductSuccess
Edited by Sid1509
forgot to add code snippet
Posted

Hi there! I see you're using React -

Proper cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE.

 

Since GSAP 3.12, we have the useGSAP() hook (the NPM package is here) that simplifies creating and cleaning up animations in React (including Next, Remix, etc). It's a drop-in replacement for useEffect()/useLayoutEffect(). All the GSAP-related objects (animations, ScrollTriggers, etc.) created while the function executes get collected and then reverted when the hook gets torn down.

 

Here is how it works:

const container = useRef(); // the root level element of your component (for scoping selector text which is optional)

useGSAP(() => {
  // gsap code here...
}, { dependencies: [endX], scope: container }); // config object offers maximum flexibility

Or if you prefer, you can use the same method signature as useEffect():

useGSAP(() => {
  // gsap code here...
}, [endX]); // simple dependency Array setup like useEffect()

This pattern follows React's best practices.

 

We strongly recommend reading the React guide we've put together at https://gsap.com/resources/React/

 

If you still need help, here's a React starter template that you can fork to create a minimal demo illustrating whatever issue you're running into. Post a link to your fork back here and we'd be happy to take a peek and answer any GSAP-related questions you have. Just use simple colored <div> elements in your demo; no need to recreate your whole project with client artwork, etc. The simpler the better. 

  • Solution
Posted

Hi,

 

Besides echoing the need of a minimal demo and the fact that you're not using our useGSAP hook, the issue could stem from the fact that the pinned element is less than the screen height (depending on the screen size of course). In those cases is better to wrap the element and the next sibling on a common ancestor and pin that particular element as shown in these demos:

See the Pen ZEVpqjb by GreenSock (@GreenSock) on CodePen.

 

See the Pen qBLRzVX by GreenSock (@GreenSock) on CodePen.

 

Hopefully this helps

Happy Tweening!

Posted
13 hours ago, Rodrigo said:

Hi,

 

Besides echoing the need of a minimal demo and the fact that you're not using our useGSAP hook, the issue could stem from the fact that the pinned element is less than the screen height (depending on the screen size of course). In those cases is better to wrap the element and the next sibling on a common ancestor and pin that particular element as shown in these demos:

 

 

 

 

 

 

Hopefully this helps

Happy Tweening!

hello @Rodrigo i dont know who you are, but for me you are a life saver, a hero, thank you, your suggestion was very on point and it worked. Thank you soo much. god bless you.

  • Like 1
Posted

Don't mention it! Glad it could help 🥳

 

Thanks for the kind words 💚

Happy Tweening!

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...