์ฌ์ดํธ๋ช
: ์ํฐํ๋ผ์ด์ฆ๋ธ๋ก์ฒด์ธ
์์
๊ธฐ๊ฐ: 5์ผ ์์
๋ผ์ด๋ธ๋ฌ๋ฆฌ: swiper, jQuery, gsap
์ ํ: PC์ ์ํ, ํด๋ก ์ฝ๋ฉ
์ฐธ์ฌ๋: 100%
GSAP + ScrollTrigger๋ฅผ ํ์ฉํ ์ ๋๋ฉ์ด์
๊ตฌํ
ScrollTrigger์ pin ์์ฑ
์ ์ฐํ ๊ฐ๋ก์ธ๋ก ์คํฌ๋กค, ์ฝ๋ฐฑ์ด๋ฒคํธ
PC๋ง ์ง์ํ๋๋ก ๋ง๋ค์๊ธฐ ๋๋ฌธ์, ์ต์๋๋น๋ฅผ 1300ํฝ์ ๋ก ์ก์์ฃผ์๋ค. ์ด๋, ์ปจํ ์ธ ์ ์ํ ์คํฌ๋กค์์ญ ๋๋ฌธ์ ๊ฐ๋ก์คํฌ๋กค์ด ์๊ธธ ์ํ์ ๋ฎ์ถ๊ธฐ ์ํด overflow-x:hidden์ ์ฌ์ฉํ๋ค.
.wrap { position: relative; min-width: 1440px; overflow-x: hidden; }
์คํฌ๋กค ๋์ค ํน์ ์์๋ฅผ ํ๋ฉด์ ๊ณ ์ ์ํค๋ ๊ธฐ๋ฅ
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'์ด๋ฒคํธ ์ฌ์ฉ
ํน์ ์์๊ฐ ๋ทฐํฌํธ(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-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 ์ฌ์ฉ์ ๋ ์ฌ์ด ๋ฐฉ๋ฒ ์๊ฐํด๋ณด๊ณ ๋ค์ด๊ฐ๊ธฐ