관리 메뉴

웹솔루션개발 25년 노하우! 해피CGI의 모든것

[해피CGI][cgimall] 스택형 카드 스크롤 애니메이션 (Stacking card) 본문

웹프로그램밍 자료실/HTML 자료

[해피CGI][cgimall] 스택형 카드 스크롤 애니메이션 (Stacking card)

해피CGI윤실장 2025. 9. 19. 09:38

세로 스크롤에 따라 카드들이 순차적으로 고정되며 확대되는 스택 효과. GSAP ScrollTrigger를 활용한 인터랙티브 디자인 예제입니다.

이 예제는 사용자가 페이지를 스크롤할 때 카드들이 하나씩 고정되면서 부드럽게 확대되는 스택(Stacking) 애니메이션 효과를 구현합니다. 각 카드가 화면 중앙에 도달하면 잠시 고정되었다가 다음 카드가 이어지는 방식으로 자연스러운 흐름을 보여주며, GSAP의 ScrollTrigger와 ScrollSmoother 플러그인을 활용하여 스크롤 위치와 애니메이션이 매끄럽게 동기화됩니다.

 

HTML 구조

<main>

  <h1>Stacking Card</h1>

 

  <div class="stacking">

    <div class="stacking__card">

      <h2>Title</h2>

      <div class="stacking__content">

        <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Consequatur error, reiciendis enim nulla voluptate non aspernatur rem dicta alias perspiciatis qui nobis ratione similique incidunt magnam ut commodi quae eaque!</p>

      </div>

    </div>

    <div class="stacking__card" style="background-color: #d6e684;">

      <h2>Title</h2>

      <div class="stacking__content">

        <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Consequatur error, reiciendis enim nulla voluptate non aspernatur rem dicta alias perspiciatis qui nobis ratione similique incidunt magnam ut commodi quae eaque!</p>

      </div>

    </div>

    <div class="stacking__card" style="background-color: #4fc1ed;">

      <h2>Title</h2>

      <div class="stacking__content">

        <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Consequatur error, reiciendis enim nulla voluptate non aspernatur rem dicta alias perspiciatis qui nobis ratione similique incidunt magnam ut commodi quae eaque!</p>

      </div>

    </div>

  </div>

 

  <section class="container">

    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iusto eum iste est aspernatur dolorum corporis hic tenetur labore voluptas dolor vitae numquam consectetur autem obcaecati quisquam ipsam eveniet, ad veritatis.</p>

    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iusto eum iste est aspernatur dolorum corporis hic tenetur labore voluptas dolor vitae numquam consectetur autem obcaecati quisquam ipsam eveniet, ad veritatis.</p>

    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iusto eum iste est aspernatur dolorum corporis hic tenetur labore voluptas dolor vitae numquam consectetur autem obcaecati quisquam ipsam eveniet, ad veritatis.</p>

    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iusto eum iste est aspernatur dolorum corporis hic tenetur labore voluptas dolor vitae numquam consectetur autem obcaecati quisquam ipsam eveniet, ad veritatis.</p>

    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iusto eum iste est aspernatur dolorum corporis hic tenetur labore voluptas dolor vitae numquam consectetur autem obcaecati quisquam ipsam eveniet, ad veritatis.</p>

    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iusto eum iste est aspernatur dolorum corporis hic tenetur labore voluptas dolor vitae numquam consectetur autem obcaecati quisquam ipsam eveniet, ad veritatis.</p>

    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iusto eum iste est aspernatur dolorum corporis hic tenetur labore voluptas dolor vitae numquam consectetur autem obcaecati quisquam ipsam eveniet, ad veritatis.</p>

  </section>

</main>



CSS 소스

@function pxToRem($pixel) {

  @return $pixel / 16 + rem;

}

 

:root {

  --black: #1f1f1f;

  --white: #fff;

}

 

body {

  background-color: var(--black);

  color: var(--white);

}

 

main {

  padding: pxToRem(50) 0;

}

 

h1 {

  color: var(--white);

  font-size: clamp(3.125rem, 17.321vw + -1.357rem, 12.5rem);

  line-height: clamp(4.688rem, 21.363vw + -0.84rem, 16.25rem);

  margin: pxToRem(100) 0;

  text-align: center;

}

 

h2 {

  font-size: clamp(1.5rem, 1.848vw + 1.022rem, 2.5rem);

  line-height: clamp(2.25rem, 1.848vw + 1.772rem, 3.25rem);

}

 

.stacking {

  position: relative;

}

 

.stacking__card {

  background-color: var(--white);

  border-radius: pxToRem(32);

  color: var(--black);

  display: flex;

  flex-direction: column;

  gap: var(--whatwedo-gap);

  margin: 25vh auto;

  max-width: pxToRem(1020);

  padding: pxToRem(32) pxToRem(32) 0;

}

 

.stacking__content {

  font-size: pxToRem(18);

  margin: pxToRem(20) 0;

  padding-bottom: pxToRem(20);

}

 

.container {

  max-width: pxToRem(800);

  margin: 0 auto;

}

 

p {

  margin: pxToRem(20) 0;

}

 



JS 소스

gsap.registerPlugin(ScrollTrigger, ScrollSmoother);

 

ScrollSmoother.create({

  smooth: 1,

  effects: true,

  normalizeScroll: true

});

 

const cards = gsap.utils.toArray(".stacking__card");

const spacer = 50;

 

cards.forEach((card, index) => {

  ScrollTrigger.create({

    trigger: card,

    start: `center-=${index * spacer} center`,

    endTrigger: ".stacking",

    end: `bottom center`,

    pin: true,

    pinSpacing: false,

    // markers: true,

    invalidateOnRefresh: true

  });

 

  const scaleValue = 0.85 + index * 0.05;

  gsap.to(card, {

    scrollTrigger: {

      trigger: card,

      start: `top center`,

      end: `bottom center`,

      scrub: true,

      // markers: true,

      invalidateOnRefresh: true

    },

    // ease: "none",

    scale: scaleValue

  });

});

 

 

 

Comments