.gallery.hidden.fixed.w-56.h-72.transform(class="top-1/2 left-1/2 -translate-y-2/4 -translate-x-2/4")
.gallery__container
ul.gallery__content
- let c = 0
while c < 50
li.gallery__card.bg-blue-200.w-56.h-72.rounded-md.absolute
.card__content
.card__title= c
- c++
.gallery__actions.absolute.top-full.flex(class="left-1/2")
button.gallery__next.bg-red-200.p-4.rounded-md Next
button.gallery__prev.bg-red-200.p-4.rounded.md Prev
View Compiled
*
box-sizing border-box
body
background hsl(220, 34%, 24%)
min-height 100vh
width calc(50 * 14rem)
padding 0
margin 0
View Compiled
import gsap from 'https://cdn.skypack.dev/gsap'
import ScrollTrigger from 'https://cdn.skypack.dev/gsap/ScrollTrigger'
const {
to,
set,
registerPlugin,
timeline,
utils: { mapRange },
} = gsap
registerPlugin(ScrollTrigger)
const CARDS = [...document.querySelectorAll('.gallery__card')]
// const GALLERY = document.querySelector('.gallery')
// const CONTENT = document.querySelector('.gallery__content')
const NEXT = document.querySelector('.gallery__next')
const PREV = document.querySelector('.gallery__prev')
let INDEX = 0
set(CARDS, {
opacity: 0,
scale: 0,
})
const RENDER = scroller => {
const NEW_INDEX = Math.floor(
mapRange(0, 1, 0, CARDS.length, scroller.progress)
)
INDEX = NEW_INDEX
const L1 = INDEX - 1 < 0 ? null : INDEX - 1
const L2 = INDEX - 2 < 0 ? null : INDEX - 2
const L3 = INDEX - 3 < 0 ? null : INDEX - 3
const U1 = INDEX + 1 > CARDS.length - 1 ? null : INDEX + 1
const U2 = INDEX + 2 > CARDS.length - 1 ? null : INDEX + 2
const U3 = INDEX + 3 > CARDS.length - 1 ? null : INDEX + 3
// console.info(INDEX, L3, L2, L1, U3, U2, U1)
const CHANGE = timeline().set(
[
...CARDS.filter(
(c, i) =>
i !== INDEX &&
i !== L1 &&
i !== L2 &&
i !== L3 &&
i !== U1 &&
i !== U2 &&
i !== U3
),
],
{
xPercent: idx => (idx < INDEX ? -400 : 400),
opacity: 0,
}
)
if (L3 !== null)
CHANGE.to(
CARDS[L3],
{
duration: 0.1,
opacity: 0,
xPercent: -300,
scale: 0,
},
0
)
if (U3 !== null)
CHANGE.to(
CARDS[U3],
{
duration: 0.1,
opacity: 0,
xPercent: 300,
scale: 0,
},
0
)
if (L2 !== null)
CHANGE.to(
CARDS[L2],
{
duration: 0.1,
opacity: 0.25,
scale: 0.25,
xPercent: -100,
},
0
)
if (L1 !== null)
CHANGE.to(
CARDS[L1],
{
duration: 0.1,
opacity: 0.5,
scale: 0.5,
xPercent: -50,
},
0
)
if (U2 !== null)
CHANGE.to(
CARDS[U2],
{
duration: 0.1,
opacity: 0.25,
scale: 0.25,
xPercent: 100,
},
0
)
if (U1 !== null)
CHANGE.to(
CARDS[U1],
{
duration: 0.1,
opacity: 0.5,
scale: 0.5,
xPercent: 50,
},
0
)
CHANGE.to(
CARDS[INDEX],
{
duration: 0.1,
opacity: 1,
scale: 1,
xPercent: 0,
},
0
)
}
const SCROLLER = ScrollTrigger.create({
horizontal: true,
scroller: document.body,
start: 'left left',
end: 'right right',
snap: 1 / 50,
markers: true,
onUpdate: self => {
const NEW_INDEX = Math.floor(mapRange(0, 1, 0, CARDS.length, self.progress))
if (CARDS[NEW_INDEX] && NEW_INDEX !== INDEX) RENDER(self)
},
})
RENDER(SCROLLER)
NEXT.addEventListener('click', () => {
SCROLLER.scroll((INDEX + 1) * (SCROLLER.end / (CARDS.length - 1)))
})
PREV.addEventListener('click', () => {
SCROLLER.scroll((INDEX - 1) * (SCROLLER.end / (CARDS.length - 1)))
})
set('.gallery', { display: 'block' })
set(document.body, { scrollLeft: 0 })
View Compiled
This Pen doesn't use any external JavaScript resources.