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

[해피CGI][cgimall] Stacking Cards on Scroll 본문

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

[해피CGI][cgimall] Stacking Cards on Scroll

해피CGI윤실장 2023. 8. 2. 17:43

마우스를 스크롤하면 카드가 쌓이는 애니메이션 효과입니다.


HTML 소스

<div class="space space--small"></div>
<div class="cards">
  <div class="card" data-index="0">
    <div class="card__inner">
      <div class="card__image-container">
        <img
          class="card__image"
          alt=""
        />
      </div>
      <div class="card__content">
        <h1 class="card__title">Card Title</h1>
        <p class="card__description">
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab dicta
          error nam eaque. Eum fuga laborum quos expedita iste saepe
          similique, unde possimus quia at magnam sed cupiditate?
          Reprehenderit, harum!
        </p>
      </div>
    </div>
  </div>
  <div class="card" data-index="0">
    <div class="card__inner">
      <div class="card__image-container">
        <img
          class="card__image"
          alt=""
        />
      </div>
      <div class="card__content">
        <h1 class="card__title">Card Title</h1>
        <p class="card__description">
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab dicta
          error nam eaque. Eum fuga laborum quos expedita iste saepe
          similique, unde possimus quia at magnam sed cupiditate?
          Reprehenderit, harum!
        </p>
      </div>
    </div>
  </div>
  <div class="card" data-index="0">
    <div class="card__inner">
      <div class="card__image-container">
        <img
          class="card__image"
          alt=""
        />
      </div>
      <div class="card__content">
        <h1 class="card__title">Card Title</h1>
        <p class="card__description">
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab dicta
          error nam eaque. Eum fuga laborum quos expedita iste saepe
          similique, unde possimus quia at magnam sed cupiditate?
          Reprehenderit, harum!
        </p>
      </div>
    </div>
  </div>
</div>
<div class="space"></div>


CSS 소스

* {
  box-sizing: border-box;
}
 
body {
  background: hsl(265.3, 10%, 75%);
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
    Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue',
    sans-serif;
}
 
.card {
  position: sticky;
  top: 0;
}
 
.card__inner {
  will-change: transform;
  background: white;
  border-radius: 14px;
  display: flex;
  overflow: hidden;
  box-shadow: 0 25px 50px -12px hsla(265.3, 20%, 10%, 35%);
  transform-origin: center top;
}
 
.cards {
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  display: grid;
  grid-template-rows: repeat(var(--cards-count), var(--card-height));
  gap: 40px 0;
}
 
.card__image-container {
  display: flex;
  width: 40%;
  flex-shrink: 0;
}
 
.card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: 1;
}
 
.card__content {
  padding: 40px 30px;
  display: flex;
  flex-direction: column;
}
 
.card__title {
  padding: 0;
  margin: 0;
  font-size: 60px;
  font-weight: 600;
  color: #16263a;
}
 
.card__description {
  line-height: 1.4;
  font-size: 24px;
  color: #16263a;
}
 
.space {
  height: 90vh;
}
 
.space--small {
  height: 40vh;
}
 
@media (max-width: 600px) {
  .card__inner {
    flex-direction: column;
  }
 
  .card__image-container {
    width: 100%;
  }
 
  .card__image {
    aspect-ratio: 16 / 9;
  }
 
  .card__title {
    font-size: 32px;
  }
 
  .card__description {
    font-size: 16px;
  }
 
  .card__content {
    padding: 30px 20px;
  }
}

JS 소스

 
const { ScrollObserver, valueAtPercentage } = aat
 
const cardsContainer = document.querySelector('.cards')
const cards = document.querySelectorAll('.card')
cardsContainer.style.setProperty('--cards-count', cards.length)
cardsContainer.style.setProperty(
  '--card-height',
  `${cards[0].clientHeight}px`
)
Array.from(cards).forEach((card, index) => {
  const offsetTop = 20 + index * 20
  card.style.paddingTop = `${offsetTop}px`
  if (index === cards.length - 1) {
    return
  }
  const toScale = 1 - (cards.length - 1 - index) * 0.1
  const nextCard = cards[index + 1]
  const cardInner = card.querySelector('.card__inner')
  ScrollObserver.Element(nextCard, {
    offsetTop,
    offsetBottom: window.innerHeight - card.clientHeight
  }).onScroll(({ percentageY }) => {
    cardInner.style.scale = valueAtPercentage({
      from: 1,
      to: toScale,
      percentage: percentageY
    })
    cardInner.style.filter = `brightness(${valueAtPercentage({
      from: 1,
      to: 0.6,
      percentage: percentageY
    })})`
  })
})


첨부된 파일 또는 해당 사이트에서 소스확인이 가능합니다

 

 

 

Comments