[๐Ÿ’ป] ์‹ค์Šต - ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ๋ธ”๋ก์ฒด์ธ

J-silverยท2025๋…„ 4์›” 9์ผ

web-project

๋ชฉ๋ก ๋ณด๊ธฐ
18/18

๐Ÿ“– Overview

์‚ฌ์ดํŠธ๋ช…: ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ๋ธ”๋ก์ฒด์ธ
์ž‘์—… ๊ธฐ๊ฐ„: 5์ผ ์†Œ์š”
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ: swiper, jQuery, gsap
์œ ํ˜•: PC์ ์‘ํ˜•, ํด๋ก  ์ฝ”๋”ฉ
์ฐธ์—ฌ๋„: 100%

๐Ÿ‘€ Check-point

GSAP + ScrollTrigger๋ฅผ ํ™œ์šฉํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ตฌํ˜„
ScrollTrigger์˜ pin ์†์„ฑ
์œ ์—ฐํ•œ ๊ฐ€๋กœ์„ธ๋กœ ์Šคํฌ๋กค, ์ฝœ๋ฐฑ์ด๋ฒคํŠธ


๐Ÿ“Œ width๊ฐ’ ๊ณ ์ •

PC๋งŒ ์ง€์›ํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ตœ์†Œ๋„ˆ๋น„๋ฅผ 1300ํ”ฝ์…€๋กœ ์žก์•„์ฃผ์—ˆ๋‹ค. ์ด๋•Œ, ์ปจํ…์ธ ์˜ ์ˆ˜ํ‰ ์Šคํฌ๋กค์˜์—ญ ๋•Œ๋ฌธ์— ๊ฐ€๋กœ์Šคํฌ๋กค์ด ์ƒ๊ธธ ์œ„ํ—˜์„ ๋‚ฎ์ถ”๊ธฐ ์œ„ํ•ด overflow-x:hidden์„ ์‚ฌ์šฉํ–ˆ๋‹ค.

.wrap {
    position: relative;
    min-width: 1440px;
    overflow-x: hidden;
}

๐Ÿ“Œ pin ์†์„ฑ

์Šคํฌ๋กค ๋„์ค‘ ํŠน์ • ์š”์†Œ๋ฅผ ํ™”๋ฉด์— ๊ณ ์ •์‹œํ‚ค๋Š” ๊ธฐ๋Šฅ

โœ pin: true

gsap.to(".sc-box", {
  scrollTrigger: {
    trigger: ".box", // ๊ณ ์ •ํ•  ํƒ€๊ฒŸ
    start: "top top", 
    end: "bottom top",
    pin: true, // ๊ณ ์ •
    markers: true
  }
});

โœ… pinSpacing

true โ†’ ๊ธฐ๋ณธ๊ฐ’, ๊ณ ์ •๋œ ์š”์†Œ๋งŒํผ ๊ณต๊ฐ„ ํ™•๋ณด
false โ†’ ๊ณ ์ •์ด ๋ ๋•Œ ๋‹ค๋ฅธ ์š”์†Œ๋“ค์ด ๊ฒน์ณ ์˜ฌ๋ผ๊ฐ€๊ฑฐ๋‚˜ ์—ฌ๋ฐฑ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ, ์—†์• ๊ณ  ์‹ถ์„๋•Œ ์‚ฌ์šฉ

// ๊ฐ€๋กœ์Šคํฌ๋กค sc-possibility
    ScrollTrigger.create({
      animation:economyTl,
      // markers:true,
      trigger:'.sc-economy',
      start:'0 0',
      end:'+=1500',
      pin:true,
      scrub:0,
      invalidateOnRefresh:true,
      onEnter:function(){
        $('.sc-economy .card-item').addClass('blur')
        $('.sc-economy .arrow-area').addClass('on')
        },
        onEnterBack:function(){
        $('.sc-economy .arrow-area').addClass('on')
        },
        onLeave:function(){
        $('.sc-economy .arrow-area').removeClass('on')
        },
        onLeaveBack:function(){
        $('.sc-economy .arrow-area').removeClass('on')
        }
    })

์˜์—ญ์— ๋“ค์–ด๊ฐ”์„๋•Œ ์ง„ํ–‰๋˜๋„๋ก 'onEnter'์ด๋ฒคํŠธ ์‚ฌ์šฉ

๐Ÿ“Œ ์ด๋ฒคํŠธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜(Event Callback Functions)

ํŠน์ • ์š”์†Œ๊ฐ€ ๋ทฐํฌํŠธ(Viewport)์— ์ง„์ž…ํ•˜๊ฑฐ๋‚˜ ๋ฒ—์–ด๋‚  ๋•Œ ์‹คํ–‰๋˜๋Š” ์ด๋ฒคํŠธ์ด๋‹ค.

ScrollTrigger.create({
  trigger: ".section",
  start: "top 80%",
  end: "bottom top",
  onEnter: () => console.log("๋“ค์–ด์˜ด"),
  onLeave: () => console.log("๋‚˜๊ฐ"),
  onEnterBack: () => console.log("๋’ค๋กœ ๋“ค์–ด์˜ด"),
  onLeaveBack: () => console.log("๋’ค๋กœ ๋‚˜๊ฐ"),
});

โœ… onEnter: ์š”์†Œ๊ฐ€ ์ฒ˜์Œ ์Šคํฌ๋กค ๋‹ค์šดํ•˜์—ฌ ํŠธ๋ฆฌ๊ฑฐ ๋ฒ”์œ„์— ๋“ค์–ด์˜ฌ ๋•Œ ์‹คํ–‰๋œ๋‹ค.
โœ… onLeave: ์š”์†Œ๊ฐ€ ์Šคํฌ๋กค ๋‹ค์šดํ•˜์—ฌ ํŠธ๋ฆฌ๊ฑฐ ๋ฒ”์œ„์—์„œ ๋ฒ—์–ด๋‚  ๋•Œ ์‹คํ–‰๋œ๋‹ค.
โœ… onEnterBack: ์š”์†Œ๊ฐ€ ์Šคํฌ๋กค ์—…ํ•˜์—ฌ ๋‹ค์‹œ ํŠธ๋ฆฌ๊ฑฐ ๋ฒ”์œ„์— ๋“ค์–ด์˜ฌ ๋•Œ ์‹คํ–‰๋œ๋‹ค.
โœ… onLeaveBack: ์š”์†Œ๊ฐ€ ์Šคํฌ๋กค ์—…ํ•˜์—ฌ ํŠธ๋ฆฌ๊ฑฐ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚  ๋•Œ ์‹คํ–‰๋œ๋‹ค.

๐Ÿ“Œ ๊ณตํ†ต์š”์†Œ


๋ฐ˜๋ณต๋˜๋Š” ์นด๋“œํ˜•ํƒœ์˜ UI์— ๊ณตํ†ต ์Šคํƒ€์ผ์„ ์ ์šฉ

<section class="sc-economy">
  <div class="split-area">
     <h3 class="title">์ „ํ†ต ๊ธˆ์œต์—์„œ<br>๋ฏธ๋ž˜ ๊ธˆ์œต์œผ๋กœ.</h3>
		<ul class="card-list">
          <li class="card-item">
             <div class="title-box">
               <em class="title">์ „ํ†ต์ž์‚ฐ</em>
               <div class="right">
               ...
             </div>
          </li>
          ...
</section>

๐Ÿ“Œ border-image

###border-image ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์š”์†Œ์˜ ํ…Œ๋‘๋ฆฌ์— ๊ทธ๋ผ๋ฐ์ด์…˜ ์ด๋ฏธ์ง€๋ฅผ ์ ์šฉํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
border-image-slice: 1;

border-image-slice๋Š” border-image๋กœ ์ง€์ •๋œ ์›๋ณธ ์ด๋ฏธ์ง€๋ฅผ ์–ด๋–ป๊ฒŒ ์ž๋ฅด๊ณ  ํ…Œ๋‘๋ฆฌ์— ์ ์šฉํ• ์ง€ ์ œ์–ดํ•˜๋Š” ์†์„ฑ์ž…๋‹ˆ๋‹ค.

๐Ÿ“Œ ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ ๊ณ„์† ํ˜๋Ÿฌ๊ฐ€๋Š” ๋ฐฐ๋„ˆ


ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ ๋์—†์ด ํ˜๋Ÿฌ๊ฐ€๋Š” ๋ฐฐ๋„ˆ๋Š” keyframe์„ ํ™œ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋‹ค.

<ul class="banner-rolling">
  <li><span>JOIN <i>us</i></span></li>
  <li><span>JOIN <i>us</i></span></li>
  <li><span>JOIN <i>us</i></span></li>
  <li><span>JOIN <i>us</i></span></li>
  <li><span>JOIN <i>us</i></span></li>
  <li><span>JOIN <i>us</i></span></li>
  ...
</ul>
.sc-banner02 .banner-rolling {
  position: relative;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: end;
      -ms-flex-pack: end;
          justify-content: flex-end;
  -webkit-animation: banner2 30s linear infinite;
          animation: banner2 30s linear infinite;
}
@-webkit-keyframes banner2 {
  0% {
    -webkit-transform: translateX(0);
            transform: translateX(0);
  }
  100% {
    -webkit-transform: translateX(100%);
            transform: translateX(100%);
  }
}

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋Š” ๊ฐ€๋กœ๋ฅผ ์žก๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋งŽ์ด ๋‚˜์„œ ๋”ฐ๋กœ ๋ฒจ๋กœ๊ทธ์— ์ •๋ฆฌํ•ด ๋‘์—ˆ๋‹ค!
์ •๋ง..์žŠ์ง€ ๋ชปํ•  ScrollTrigger์˜€๋‹ค..
-> pin์œผ๋กœ๋งŒ ๋ชจ๋“ ๊ฑธ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ•ด์„œ ์˜ค๋ฅ˜๊ฐ€ ๋งŽ์ด ๋‚ฌ๋˜๊ฒƒ! ํ•ด๊ฒฐ๋ฐฉ์•ˆ ๋‹ค์‹œ ์ •๋ฆฌ!!


์‚ฌ์ด์ฆˆ๋ฅผ ์ถ•์†Œํ•ด๋ณด๋‹ˆ ์˜ค๋ฅ˜ ๋ฐœ๊ฒฌ๐Ÿค”

100%์ผ๋• ๋†’์ด๊ฐ€ 100vh๋กœ ์ž˜ ์žกํ˜”๋Š”๋ฐ ์ค„์ด๋‹ˆ ์ž๋™์œผ๋กœ ์žก์•„์ฃผ์ง€ ์•Š๋Š”๋‹ค.
-> ์ ์‘ํ˜•์œผ๋กœ ์ž‘์—…ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ScrollTrigger์—๊ฒŒ ์ž๋™ ๋†’์ด ๊ณ„์‚ฐ ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์ฃผ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ!

3๊ฐ€์ง€ ํ•ด๊ฒฐ๋ฐฉ์•ˆ
1. invalidateOnRefresh: true
2. pinSpacing: true
3. sticky์‚ฌ์šฉํ•˜๊ธฐ


before์„ ์ด์šฉํ•ด์„œ ํฐ๋ฐฐ๊ฒฝ์„ ์ฃผ์—ˆ๋”๋‹ˆ ํ™•๋Œ€์‹œ ์˜ค๋ฅ˜๋ฐœ์ƒ
border-image๋ฅผ ์ด์šฉํ•˜๊ธฐ!

1. border-left: 0;
์™ผ์ชฝ์„ ์—†์• ์ฃผ๋ฉด ํ•ด๊ฒฐ!


์ ์‘ํ˜•์ด์ง€๋งŒ ํ™”๋ฉด์ด ์ค„์–ด๋“ค์‹œ ์—ฌ๋ฐฑ ๋ฐœ์ƒ๐Ÿค”
๋ฌธ์ œ1 ๊ฐ€๋กœ์Šคํฌ๋กค์ด width๊ฐ’ ๋ชป์žก์Œ
-> width: max-content; or width: 100%
๋ฌธ์ œ2 ๋งˆ์ง€๋ง‰ ์Šคํฌ๋กค ๋’ค์— ์—ฌ๋ฐฑ์ƒ๊น€

๊ธฐ์กด์ฝ”๋“œ

 .to('.sc-economy .split-area',{
        x: function() {
            return -economyWidth;
          },
          ease: "none",
          duration:4
    },'z')

.split-area๋ฅผ (์ „์ฒด ์นด๋“œ ๋„ˆ๋น„ - ๋ทฐํฌํŠธ ๋„ˆ๋น„) ๋งŒํผ๋งŒ ์ด๋™์‹œ์ผœ์•ผ ํ•˜๋Š”๋ฐ,
-economyWidth๋Š” ํ•œ ํ™”๋ฉด ๋” ๋งŽ์ด ์ด๋™ํ•ด๋ฒ„๋ฆฌ๋Š” ์…ˆ

์ˆ˜์ •์ฝ”๋“œ

economyTl
    .to(".sc-economy .split-area",{
        xPercent:-100,
        x:"100vw",
        duration:4
    },'z')

xPercent: -100
=> .split-area ์ „์ฒด ๋„ˆ๋น„์˜ 100%๋งŒํผ ์™ผ์ชฝ์œผ๋กœ ์ด๋™
ํ•˜์ง€๋งŒ ์ƒ๋Œ€์ด๋™์ด๋ผ ์ž๊ธฐ ๋„ˆ๋น„๋งŒํผ ์›€์ง์ด๊ธฐ ๋•Œ๋ฌธ์— ํ™”๋ฉด์— ๋”ฑ ๋งž์ง€ ์•Š์„์ˆ˜์žˆ๋‹ค.
x: "100vw"
์—ฌ๊ธฐ์— ์ถ”๊ฐ€๋กœ ํ™”๋ฉด ๋„ˆ๋น„๋งŒํผ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ด๋™
์ฆ‰, ์œ„์—์„œ ๋„ˆ๋ฌด ๋งŽ์ด ๋ฐ€๋ฆฐ ๊ฑธ ํ•œ ํ™”๋ฉด ๋งŒํผ ๋‹ค์‹œ ์•ž์œผ๋กœ ๋‹น๊ธด ํšจ๊ณผ
ex) -300vw + 100vw = -200vw

โœ gsap pin์€ ๋งŒ๋Šฅ์ด ์•„๋‹ˆ๋‹ค!
sticky๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ๋” ๋น ๋ฅด๊ณ  ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค!
gsap ์‚ฌ์šฉ์ „ ๋” ์‰ฌ์šด ๋ฐฉ๋ฒ• ์ƒ๊ฐํ•ด๋ณด๊ณ  ๋“ค์–ด๊ฐ€๊ธฐ

profile
๋‹ฌ๋ฆฌ๋Š” ๊ฑฐ๋ถ์ด

0๊ฐœ์˜ ๋Œ“๊ธ€