OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Using GSAP / ScrollTrigger to create card stacking effect on scroll

  • Thread starter Thread starter Freddy
  • Start date Start date
F

Freddy

Guest
I'm trying to mimic the an effect where cards unstack on scroll. For visuals, please click here to view a GIF of the effect.

The website the above GIF is from is this website.

Now, I've tried to mimic the above using GSAP / ScrollTrigger. However, my effect differs in the following aspects:

  1. The cards stack on top of each other in my demo, but reveal themselves in the demo I'm trying to mimic (see image of the design I'm trying to achieve below). I've tried z-indexing but this didn't do the trick.
  2. The cards pin to the top of the page, whereas I'm looking for it to be centered.
  3. It doesn't unpin when you've passed .cardStacking (carries on until the end of the page)

enter image description here

Demo (view on 1200px +)


Code:
$(function() {

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

  cards.forEach((card, index) => {
    const tween = gsap.to(card, {
      scrollTrigger: {
        trigger: card,
        start: () => `top bottom-=100`,
        end: () => `top top+=40`,
        scrub: true,
        markers: true,
        invalidateOnRefresh: true
      },
      ease: "none",
      scale: () => 1 - (cards.length - index) * 0.025
    });

    ScrollTrigger.create({
      trigger: card,
      start: "top top",
      pin: true,
      pinSpacing: false,
      markers: true,
      id: 'pin',
      end: 'max',
      //end: '.cardStacking',
      invalidateOnRefresh: true,
    });

  });

});

Code:
:root {
  --navy: #0E185F;
  --white: #FFFFFF;
}

.background--navy {
  background-color: var(--navy);
}

.color--white {
  color: var(--white);
}

.spacer {
  height: 2000px;
}

.cardStacking {
  padding: 120px 0 141px 0;
  /*********/
}
.cardStacking__intro {
  margin-bottom: 100px;
}
.cardStacking .stackCard {
  border-radius: 40px;
  background: linear-gradient(90deg, #c7defe 0%, #e7e7f2 100%);
  margin-bottom: 50px;
  padding: 106px 135px 126px 77px;
  /* CONTENT */
}
.cardStacking .stackCard:first-child {
  box-shadow: 0px 10px 30px 0px rgba(0, 0, 0, 0.16);
}
.cardStacking .stackCard__content-header {
  margin-bottom: 10px;
}

Code:
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js"></script>

<div class="spacer"></div>

<section class="cardStacking background--navy">
  <div class="container">

    <div class="row justify-content-center">
      <div class="col-12 col-md-10 col-lg-7">
        <div class="cardStacking__intro text-center">
          <h2 class="cardStacking__intro-header color--white">LOREM IPSUM DOLOR SIT AMET CONSETETUR SADIPSCING</h2>
          <div class="cardStacking__intro-copy color--white">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.</div>
        </div>
      </div>
    </div>

    <div class="row justify-content-center">
      <div class="col-12 col-md-10">
        <div class="cardStacking__cards">
  
            <!------------>
            <!-- CARD 1 -->
            <!------------>
          
            <div class="stackCard">
              <div class="stackCard__content">
                <span class="stackCard__content-header d-block">Header</span>
                <div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
              </div>
            </div>
          
            <!------------>
            <!-- CARD 2 -->
            <!------------>
            <div class="stackCard">
              <div class="stackCard__content">
                <span class="stackCard__content-header d-block">Header 2</span>
                <div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
              </div>
            </div>
          
            <!------------>
            <!-- CARD 3 -->
            <!------------>
            <div class="stackCard">
              <div class="stackCard__content">
                <span class="stackCard__content-header d-block">Header 3</span>
                <div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
              </div>
            </div>

        </div>
      </div>
    </div>

  </div>
</section>

<div class="spacer"></div>

Edit:

I have managed to somewhat resolve items 1 and 3 in my above list.

However, the functionality for item 1 isn't quite there yet. I do not know why the cards are not stacked upon each other and are not centered.

See updated demo here:


Code:
$(function() {

   const container = document.querySelector(".cardStacking__cards");
  const card = document.querySelector(".stackCard");
  const cards = document.querySelectorAll(".stackCard");
  const height = 500;

  const timeline = gsap.timeline({
    scrollTrigger: {
      trigger: container,
      pin: true,
      markers: true,
      scrub: 1,
      start: "bottom-=10% center",
      end: "bottom top"
    }
  });

  timeline.from(card, {
    y: (index) => height * (cards.length - (index + 1)),
    duration: (index) => 0.6 / (index + 1),
    ease: "none",
    stagger: (index) => 0.3 * (index),
  });

});

Code:
:root {
  --navy: #0E185F;
  --white: #FFFFFF;
}

.background--navy {
  background-color: var(--navy);
}

.color--white {
  color: var(--white);
}

.spacer {
  height: 2000px;
}

.cardStacking {
  padding: 120px 0 141px 0;
  /*********/
}
.cardStacking__intro {
  margin-bottom: 100px;
}
.cardStacking .stackCard {
  border-radius: 40px;
  background: linear-gradient(90deg, #c7defe 0%, #e7e7f2 100%);
  margin-bottom: 50px;
  padding: 106px 135px 126px 77px;
  /* CONTENT */
}
.cardStacking .stackCard:first-child {
  box-shadow: 0px 10px 30px 0px rgba(0, 0, 0, 0.16);
}
.cardStacking .stackCard__content-header {
  margin-bottom: 10px;
}

Code:
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js"></script>

<div class="spacer"></div>

<section class="cardStacking background--navy">
  <div class="container">

    <div class="row justify-content-center">
      <div class="col-12 col-md-10 col-lg-7">
        <div class="cardStacking__intro text-center">
          <h2 class="cardStacking__intro-header color--white">LOREM IPSUM DOLOR SIT AMET CONSETETUR SADIPSCING</h2>
          <div class="cardStacking__intro-copy color--white">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.</div>
        </div>
      </div>
    </div>

    <div class="row justify-content-center">
      <div class="col-12 col-md-10">
        <div class="cardStacking__cards">
  
            <!------------>
            <!-- CARD 1 -->
            <!------------>
          
            <div class="stackCard" style="z-index: 0;">
              <div class="stackCard__content">
                <span class="stackCard__content-header d-block">Header</span>
                <div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
              </div>
            </div>
          
            <!------------>
            <!-- CARD 2 -->
            <!------------>
            <div class="stackCard" style="z-index: -1;">
              <div class="stackCard__content">
                <span class="stackCard__content-header d-block">Header 2</span>
                <div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
              </div>
            </div>
          
            <!------------>
            <!-- CARD 3 -->
            <!------------>
            <div class="stackCard" style="z-index: -2;">
              <div class="stackCard__content">
                <span class="stackCard__content-header d-block">Header 3</span>
                <div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
              </div>
            </div>

        </div>
      </div>
    </div>

  </div>
</section>

<div class="spacer"></div>

<p>I'm trying to mimic the an effect where cards unstack on scroll. For visuals, <a href=" " rel="nofollow noreferrer">please click here to view a GIF of the effect</a>.</p>
<p>The website the above GIF is from is <a href="https://www.createwithplay.com/" rel="nofollow noreferrer">this website</a>.</p>
<p>Now, I've tried to mimic the above using GSAP / ScrollTrigger. However, my effect differs in the following aspects:</p>
<ol>
<li>The cards stack on top of each other in my demo, but reveal themselves in the demo I'm trying to mimic (see image of the design I'm trying to achieve below). I've tried <code>z-indexing</code> but this didn't do the trick.</li>
<li>The cards pin to the top of the page, whereas I'm looking for it to be centered.</li>
<li>It doesn't unpin when you've passed <code>.cardStacking</code> (carries on until the end of the page)</li>
</ol>
<p><a href="https://i.sstatic.net/c194n.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/c194n.png" alt="enter image description here" /></a></p>
<p><strong>Demo (view on 1200px +)</strong></p>
<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>$(function() {

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

cards.forEach((card, index) => {
const tween = gsap.to(card, {
scrollTrigger: {
trigger: card,
start: () => `top bottom-=100`,
end: () => `top top+=40`,
scrub: true,
markers: true,
invalidateOnRefresh: true
},
ease: "none",
scale: () => 1 - (cards.length - index) * 0.025
});

ScrollTrigger.create({
trigger: card,
start: "top top",
pin: true,
pinSpacing: false,
markers: true,
id: 'pin',
end: 'max',
//end: '.cardStacking',
invalidateOnRefresh: true,
});

});

});</code></pre>
<pre class="snippet-code-css lang-css prettyprint-override"><code>:root {
--navy: #0E185F;
--white: #FFFFFF;
}

.background--navy {
background-color: var(--navy);
}

.color--white {
color: var(--white);
}

.spacer {
height: 2000px;
}

.cardStacking {
padding: 120px 0 141px 0;
/*********/
}
.cardStacking__intro {
margin-bottom: 100px;
}
.cardStacking .stackCard {
border-radius: 40px;
background: linear-gradient(90deg, #c7defe 0%, #e7e7f2 100%);
margin-bottom: 50px;
padding: 106px 135px 126px 77px;
/* CONTENT */
}
.cardStacking .stackCard:first-child {
box-shadow: 0px 10px 30px 0px rgba(0, 0, 0, 0.16);
}
.cardStacking .stackCard__content-header {
margin-bottom: 10px;
}</code></pre>
<pre class="snippet-code-html lang-html prettyprint-override"><code><link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js"></script>

<div class="spacer"></div>

<section class="cardStacking background--navy">
<div class="container">

<div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-7">
<div class="cardStacking__intro text-center">
<h2 class="cardStacking__intro-header color--white">LOREM IPSUM DOLOR SIT AMET CONSETETUR SADIPSCING</h2>
<div class="cardStacking__intro-copy color--white">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.</div>
</div>
</div>
</div>

<div class="row justify-content-center">
<div class="col-12 col-md-10">
<div class="cardStacking__cards">

<!------------>
<!-- CARD 1 -->
<!------------>

<div class="stackCard">
<div class="stackCard__content">
<span class="stackCard__content-header d-block">Header</span>
<div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
</div>
</div>

<!------------>
<!-- CARD 2 -->
<!------------>
<div class="stackCard">
<div class="stackCard__content">
<span class="stackCard__content-header d-block">Header 2</span>
<div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
</div>
</div>

<!------------>
<!-- CARD 3 -->
<!------------>
<div class="stackCard">
<div class="stackCard__content">
<span class="stackCard__content-header d-block">Header 3</span>
<div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
</div>
</div>

</div>
</div>
</div>

</div>
</section>

<div class="spacer"></div></code></pre>
</div>
</div>
</p>
<p><strong>Edit:</strong></p>
<p>I have managed to somewhat resolve items 1 and 3 in my above list.</p>
<p>However, the functionality for item 1 isn't quite there yet. I do not know why the cards are not stacked upon each other and are not centered.</p>
<p>See updated demo here:</p>
<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>$(function() {

const container = document.querySelector(".cardStacking__cards");
const card = document.querySelector(".stackCard");
const cards = document.querySelectorAll(".stackCard");
const height = 500;

const timeline = gsap.timeline({
scrollTrigger: {
trigger: container,
pin: true,
markers: true,
scrub: 1,
start: "bottom-=10% center",
end: "bottom top"
}
});

timeline.from(card, {
y: (index) => height * (cards.length - (index + 1)),
duration: (index) => 0.6 / (index + 1),
ease: "none",
stagger: (index) => 0.3 * (index),
});

});</code></pre>
<pre class="snippet-code-css lang-css prettyprint-override"><code>:root {
--navy: #0E185F;
--white: #FFFFFF;
}

.background--navy {
background-color: var(--navy);
}

.color--white {
color: var(--white);
}

.spacer {
height: 2000px;
}

.cardStacking {
padding: 120px 0 141px 0;
/*********/
}
.cardStacking__intro {
margin-bottom: 100px;
}
.cardStacking .stackCard {
border-radius: 40px;
background: linear-gradient(90deg, #c7defe 0%, #e7e7f2 100%);
margin-bottom: 50px;
padding: 106px 135px 126px 77px;
/* CONTENT */
}
.cardStacking .stackCard:first-child {
box-shadow: 0px 10px 30px 0px rgba(0, 0, 0, 0.16);
}
.cardStacking .stackCard__content-header {
margin-bottom: 10px;
}</code></pre>
<pre class="snippet-code-html lang-html prettyprint-override"><code><link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js"></script>

<div class="spacer"></div>

<section class="cardStacking background--navy">
<div class="container">

<div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-7">
<div class="cardStacking__intro text-center">
<h2 class="cardStacking__intro-header color--white">LOREM IPSUM DOLOR SIT AMET CONSETETUR SADIPSCING</h2>
<div class="cardStacking__intro-copy color--white">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.</div>
</div>
</div>
</div>

<div class="row justify-content-center">
<div class="col-12 col-md-10">
<div class="cardStacking__cards">

<!------------>
<!-- CARD 1 -->
<!------------>

<div class="stackCard" style="z-index: 0;">
<div class="stackCard__content">
<span class="stackCard__content-header d-block">Header</span>
<div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
</div>
</div>

<!------------>
<!-- CARD 2 -->
<!------------>
<div class="stackCard" style="z-index: -1;">
<div class="stackCard__content">
<span class="stackCard__content-header d-block">Header 2</span>
<div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
</div>
</div>

<!------------>
<!-- CARD 3 -->
<!------------>
<div class="stackCard" style="z-index: -2;">
<div class="stackCard__content">
<span class="stackCard__content-header d-block">Header 3</span>
<div class="stackCard__content-copy">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</div>
</div>
</div>

</div>
</div>
</div>

</div>
</section>

<div class="spacer"></div></code></pre>
</div>
</div>
</p>
 
Top