ํ๋ซํผ์ ์ฌ์ฉํ๋ ๋์์ ์คํฌ๋กค ๊ฒฝํ์ ํ์คํํ๊ณ ๋งค์ฐ ๋ถ๋๋ฌ์ด ํ์ ๊ธฐ๋ฅ์ผ๋ก ์น์ฌ์ดํธ๋ฅผ ๊ฐํํ๊ธฐ ์ํด ๊ตฌ์ถ๋ ์คํ ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์ค์น
โ ํจํค์ง ๊ด๋ฆฌ์
$ npm i @studio-freight/lenis
import Lenis from '@studio-freight/lenis'
โก ์คํฌ๋ฆฝํธ
<script src="https://unpkg.com/@studio-freight/lenis@1.0.32/dist/lenis.min.js"></script>
์ค์
[๊ธฐ๋ณธ์ค์ ]
const lenis = new Lenis()
lenis.on('scroll', (e) => {
console.log(e)
})
function raf(time) {
lenis.raf(time)
requestAnimationFrame(raf)
}
requestAnimationFrame(raf)
GSAP ScrollTrigger๋ฅผ ๊ฐ์ด ์ฌ์ฉํ๋ค๋ฉด?
const lenis = new Lenis()
lenis.on('scroll', ScrollTrigger.update)
gsap.ticker.add((time)=>{
lenis.raf(time * 1000)
})
gsap.ticker.lagSmoothing(0)
- body์ overflow: hidden ์๋ฉธ
- gsap๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ฉด์ lenis ์๋wrapper ๋ณ๊ฒฝ์ ๋ฌธ์ ๋ฐ์
body์ overflow: hidden ์๋ฉธ
lenis๋ฅผ ์ฌ์ฉํ๋ฉด body์ ์ค overflow: hidden์ด ์์ฉ์์ด์ง์ ํ์ธํจ,
๋ํ ๋ฒํผ ํด๋ฆญ์ ํ์ฑํ๋๋ gnb(๋ค๋น๊ฒ์ด์
)์ ๋ด๋ถ์์ ์คํฌ๋กค์ด ๋์ง์๋ ํ์ ๋ฐ์.
ํด๋น ๋ฌธ์ ๋ Lenis.github ์ ๊ณ ๋ ค์ฌํญ์ผ๋ก ์ ์ด๋ ์ค์ฒฉ ์คํฌ๋กค
์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด ํด๊ฒฐ๋๋ค.
<div data-lenis-prevent>scroll content</div>
<div data-lenis-prevent-wheel>scroll content</div>
<div data-lenis-prevent-touch>scroll content</div>
๐
๋๊ฐ์ ๊ฒฝ์ฐ gnb๋ด๋ถ ์คํฌ๋กค์ด ๋์ง ์์์,
<nav class="gnb" data-lenis-prevent-wheel>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</nav>
์ด๋ฐ์์ผ๋ก ๋ฃ์ด์คฌ๋๋ ์คํฌ๋กค์ด ์ ์๋๋๋ ๊ฑธ ํ์ธํ๋ค.
gsap๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ฉด์ lenis ์๋wrapper ๋ณ๊ฒฝ์ ๋ฌธ์ ๋ฐ์
lenis๋ฅผ ์ฌ์ฉํ๋ฉด ์คํฌ๋กค์ด ์ ์ฉ๋๋ ์ปจํ
์ด๋(wrapper)๊ฐ ์๋์ผ๋ก html๋ก ์ ์ฉ๋๋๋ฐ,
UI์ html์ด ์๋ ๋ด๋ถ ์ปจํ
์ธ div(.wrapper)๋ก ๋ณ๊ฒฝํด์ผ ํ๋ ์ํฉ์ด์์.
<html lenis lenis-smooth>
Lenis.github ์ ๋ณด๋ฉด Instance settings ์ wrapper
๋ผ๋ ์ต์
์ด ์๋ค.
const lenis = new Lenis({
wrapper: document.querySelector('.container'),
});
๋จ์ํ ์ด๋ ๊ฒ ๋ณ๊ฒฝํ๋ฉด ๋ ์ค ์์๋๋ ๋งํฌ์
์ ๋ณ๊ฒฝ๋ง๋ ๋ฟ ์คํฌ๋กค์ด ์๋จน๋๋ค.
์ด๋์ ๋ ํด๊ฒฐํ ๋ฐฉ๋ฒ์๐
[ JS ]
const lenis = new Lenis({
wrapper: document.querySelector('.wrapper'),
content: document.querySelector('.inner-wrapper'),
});
lenis.on('scroll', ScrollTrigger.update);
gsap.ticker.add(time => {
lenis.raf(time * 1000);
});
gsap.ticker.lagSmoothing(0);
[ CSS ]
html {
bottom: 0;
left: 0;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
}
.wrapper {
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
overflow: hidden;
overflow-y: auto;
width: 100%;
}
์ฌ๊ธฐ๊น์ง ํ๋ฉด ์คํฌ๋กค์ smoothํ๊ฒ ๋์์ด ์๋๋ค.
but...... ์ถ๊ฐ์ ์ผ๋ก ๋ฐ์ํ ๋ฌธ์ ๐ซ
js ์ด๋ฒคํธ ๋ฆฌ์ค๋(scroll)
๊ฐ ๋์ํ์ง ์์gsap scrollTrigger ์๋์๋จ
์ด๊ฑด gsap scrollTrigger์ ์์ฑ์ผ๋ก ํด๊ฒฐํ๋ค.
๋ด๊ฐ scrollTrigger ๋ฃ์ด์ค ๊ณณ๋ง๋ค scroller์์ฑ๊ฐ์ ๋ฃ์ด์ค์ผํ๋ค.
ํด๊ฒฐ๐
scrollTrigger: {
trigger: 'section',
scroller: '.wrapper',
}
js ์คํฌ๋กค ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๋์์๋จ
window์์ฒด ์คํฌ๋กค์ ํ๊ณ ์๋๊ฒ ์๋, lenis์ gsap์ผ๋ก ๊ฐ์ ์คํฌ๋กค ์ค์ด๋ผ scroll์์น๊ฐ์ ๋ชป์ฝ์.
์ด๋ฒคํธ ๋ฆฌ์ค๋๋์ gsap์ผ๋ก ๋์ฒด ํด๊ฒฐ๊ฐ๋ฅ
ํด๊ฒฐ๐
์น์ ๋ณ๋ก ํ์ํ๋ ๊ธฐ๋ฅ๋ค์ ์๋์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝํด์ฃผ๋ ๊ฑธ๋ก ๋์ฒดํจ.
ScrollTrigger.create({
trigger: 'section',
scroller: '.wrapper',
start: '0% 0%',
onEnter: function () {
$('section .con').addClass('on');
},
onLeaveBack: function () {
$('section .con').removeClass('on');
},
});
ex) scrollTop๊ฐ์ด 0์ด๊ณผ์ผ๋๋ง ์ ์ฉ๋๋ header์์๋ ์๋์ ๊ฐ์ด,
ScrollTrigger.create({
trigger: '.wrapper',
scroller: '.wrapper',
onUpdate: self => {
// console.log('progress:', self.progress.toFixed(3));
if (self.progress.toFixed(3) > 0.5) {
$('.header').addClass('on');
} else {
$('.header').removeClass('on');
}
},
});
gsap.update ์ค๋ช
gsap.progress ์ค๋ช
๋ฌธ์ ํด๊ฒฐ ๋...๐ซ