How to CSS animate a hand-made carousel?

3 weeks ago 32
ARTICLE AD BOX

I'm working on a React hand-made horizontal carousel component but I'm struggling making an animation to slide the carousel when clicking the respective chevron image.

Do you have any idea how to do it?

This is my component.tsx?

import { useState } from 'react' // Styles import './Carousel.component.style.css' // Assets import leftsideChevron from '../../assets/images/LeftsideChevron.svg' import rightsideChevron from '../../assets/images/RightsideChevron.svg' const CarouselComponent = ({ itemsList, }: { itemsList: { title: string image: string }[] }) => { const [currentIndex, setCurrentIndex] = useState(0) const aux = 4 const onLeftClick = () => { if (currentIndex === 0) { return } console.log('currentIndex (left): ' + currentIndex) if (currentIndex <= aux) { setCurrentIndex(0) return } if (currentIndex - aux >= 0) { setCurrentIndex((value) => Math.max(0, value - aux)) } } const onRightClick = () => { if (currentIndex === itemsList.length) { return } console.log('currentIndex (right): ' + currentIndex) if (currentIndex + aux >= itemsList.length) { setCurrentIndex(itemsList.length) return } setCurrentIndex((value) => Math.min(value + aux, Math.max(0, itemsList.length - aux)), ) } return ( <div className="carouselContainer"> <img alt="leftside chevron" className="carouselLeftsideChevron" onClick={onLeftClick} src={leftsideChevron} /> <div className="itemsListContainer"> {itemsList.map((item, id) => { return ( <div className="itemContainer" key={item.title + id.toString()} > <img alt={item.image} src={item.image} /> <p>{item.title}</p> </div> ) })} </div> <img alt="rightside chevron" className="carouselRightsideChevron" onClick={onRightClick} src={rightsideChevron} /> </div> ) } export default CarouselComponent

And this is my CSS file:

@import '../../assets/globals.css'; .carouselContainer { display: flex; justify-content: space-between; padding-top: 1em; } .itemsListContainer { display: flex; flex: 1 0 20%; overflow-x: auto; overflow: hidden; padding: 1em 0; scroll-snap-type: x mandatory; } .itemContainer { border-radius: 1em; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25); display: flex; gap: 1em; justify-content: center; margin: 0.2em 1em; min-width: 20%; scroll-margin-left: 1em; scroll-snap-align: start; max-width: 25%; } .itemContainer img { height: auto; width: 2.43rem; } .itemContainer p { font-family: Montserrat-Bold; font-size: 1.5rem; } .carouselRightsideChevron:hover, .carouselLeftsideChevron:hover { cursor: pointer; }

Here is a screenshot for the component on screen:

Component on screen


What have I tried so far is to update my code to try this out:

const onLeftClick = () => { setCurrentIndex((prev) => Math.max(prev - aux, 0)) } const onRightClick = () => { setCurrentIndex((prev) => Math.min(prev + aux, itemsList.length - aux) ) } ... <div className="itemsViewport"> <div className="itemsListContainer" style={{ transform: `translateX(-${currentIndex * 100 / aux}%)`, }} > {itemsList.map((item, id) => ( <div className="itemContainer" key={item.title + id} > <img alt={item.image} src={item.image} /> <p>{item.title}</p> </div> ))} </div> </div>

In combination with this CSS:

.itemsViewport { overflow: hidden; width: 100%; } .itemsListContainer { display: flex; transition: transform 0.4s ease-in-out; } .itemContainer { flex: 0 0 25%; text-align: center; }

This wasn't a solution for my situation because it was not snaping my overflow-x to the very end of the carousel items. It ended up somewhere near the 60% of the overflow-x total width.

Read Entire Article