프론트엔드 개발자라면, 캐러셀 구현은 피해갈 수 없는 운명이라고 할 수 있을 것 같다.
UI 디자인도 겸하며 느끼는 점이... 디자인 할 때 가장 요긴한게 캐러셀이기 때문이다.
어디에 넣어도 보기에 반 이상은 가는 느낌이 드는 것이 캐러셀이기에, 시안을 보면 캐러셀은 정말 항상 있다.. 항상.
캐러셀을 직접 구현하는 것은 생각보다 까다롭고, 복잡한 일이다.
분명 본인만의 캐러셀을 만들어 놓고 사용하는 사람들도 있겠지만, 대개 디자인에 따라서 조금씩 달라지기 때문에 미리 만들어 놓기도 힘들다.
그래서 내 주변 프론트엔드 개발자들은 더 좋은 캐러셀 라이브러리를 찾고자 하는 욕구를 항상 갖고있다. (...)
필자 역시 마찬가지이고, 그렇게 찾고 찾던 중 개쩌는 캐러셀 라이브러리를 찾았다.
사실 사용한지 꽤 됐는데 피치 못할 사정(개귀찮음)이 있어서 공유할 생각을 안하다가... 이번에 또 구현할 일이 생겨 작성하게 되었다.
라이브러리를 사용할 때 중요하게 생각하는 점을 뽑자면,
- 공식문서의 친절함
- 예제코드의 존재
- 커뮤니티
- 캐러셀 라이브러리라면, 커스텀의 자유도까지
정도가 될 것 같다.
우선 이 라이브러리는 공식문서가 개쩐다...
캐러셀 라이브러리 중 유명한 react-slick
과 비교해보았다.
둘이 비교하면 react-slick
이 기분 나빠 할 수준.
그럼에도 이 녀석의 공식문서에는 낭만이 있다...
설명도 깔끔하고, 필요한 예제가 전부 나와있으며 여느 메이저 라이브러리/프레임워크의 공식문서를 가뿐히 넘어버리는 수준이다.
별별 상황에서 사용할 수 있는 캐러셀 예제가 다 나와있다.
심지어 고착화 된 코드가 아니라, 사용자가 유동적으로 변경하여 사용할 수 있다.
심지어 가볍고, 자연스러우며, 부드럽다!
사실 커뮤니티가 조금 약하다.
npm trend
에서도 알 수 있듯, 다른 캐러셀 라이브러리에 비해 아직은 아기이기 때문에... 어쩔 수 없는 부분이라고 생각한다.
이 글은 리액트에서 해당 라이브러리를 이용하는 것이므로, embla-carousel-react
를 설치할 것이다.
$ npm install embla-carousel-react --save
or
$ yarn add embla-carousel-react
embla-carousel
을 typescript
로 이용하고 싶다?!
패키지 내부에 type이 모두 정의되어 있기 때문에, 그냥 저것만 설치하면 된다!
이번에 구현할 캐러셀은, 아래 시안과 같이 양 옆의 요소가 살짝 보이는 캐러셀이다.
시안에 맞게 구현할 예제 코드를 찾아본다.
본 프로젝트에서는 위 형태의 캐러셀을 다양한 곳에서 사용하기 때문에, 재사용할 수 있도록 슬라이드의interface
를 구성하였다.
본인의 프레임워크 / 언어에 맞게 코드 샌드박스를 생성할 수 있다.
필자의 경우에는 해당 예제를 커스텀하기로 결정했다.
파일 구조는 위 이미지와 같다.
option
과 각 슬라이드에 들어갈 아이템을 전달해주는 역할을 한다.embla-carousel
을 사용하여 구현하였다.//공통 캐러셀 래퍼 컴포넌트
import { EmblaOptionsType } from "embla-carousel-react";
import Carousel from "./Carousel";
import { CarouselItem } from "../../interfaces/CarouselItem";
import "./CarouselStyle.scss";
interface CarouselProps {
items: Array<CarouselItem>;
}
const CarouselWrapper = (props: CarouselProps) => {
const { items } = props;
const OPTIONS: EmblaOptionsType = { align: "center", loop: true };
return (
<section className="sandbox__carousel">
<Carousel slides={items} options={OPTIONS} />
</section>
);
};
export default CarouselWrapper;
option
의 경우에는 공식문서-옵션을 통해 유동적으로 변경해주면 된다.
필자의 경우에는 루프 옵션이 필요하여 추가했다.
import useEmblaCarousel, { EmblaOptionsType } from "embla-carousel-react";
import { CarouselItem } from "../../interfaces/CarouselItem";
import "./CarouselStyle.scss";
type PropType = {
slides: Array<CarouselItem>;
options?: EmblaOptionsType;
};
const EmblaCarousel: React.FC<PropType> = (props) => {
const { slides, options } = props;
const [emblaRef] = useEmblaCarousel(options);
return (
<div className="embla">
<div className="embla__viewport" ref={emblaRef}>
<div className="embla__container">
{slides.map((slide, index) => (
<div className="embla__slide" key={index}>
<img className="embla__slide__img" src={slide.img} />
<span
className="embla__slide__link"
onClick={() => window.open(`${slide.url}`)}
>
자세히보기
</span>
</div>
))}
</div>
</div>
</div>
);
};
export default EmblaCarousel;
embla__slide
는 본인이 아이템으로 가져갈 슬라이드를 유동적으로 구성해주면 된다!
위 CarouselItem
인터페이스는 img와 url로 이루어져있다.
.sandbox__carousel {
position: relative;
}
$slide-spacing: 20px;
.embla__viewport {
overflow: hidden;
}
.embla__container {
display: flex;
flex-direction: row;
margin-left: -20px;
}
.embla__slide {
padding-left: $slide-spacing;
position: relative;
& > img {
width: 320px;
display: block;
object-fit: cover;
@media screen and (min-width: 500px) {
min-width: 360px;
}
}
& > .embla__slide__link {
cursor: pointer;
position: absolute;
bottom: 10px;
right: 15px;
text-decoration: underline;
color: white;
font-size: 10px;
}
}
scss
로 작성되었지만, mixin
같은 문법이 사용되지 않았기 때문에 형식만 잘 맞추어 css
styled-component
styled jsx
tailwind
등에서 사용하면된다.
참고로 공식문서의 예제는 일반 css
로 되어있다!
모바일 중심으로 리팩토링 중인 웹 서비스이기에, 뷰 크기가 저정도이다.
직접 구현하는 것이 실력 향상에 크게 도움이 된다고 하지만, 가끔 그냥 라이브러리를 잘 쓰는 것이 시간(금)을 아끼는 방법이라고 느낄 때가 많다.
특히 캐러셀은... 좋은 라이브러리를 찾으면 더더욱 좋은듯!
물론 react-slick
등 기존의 캐러셀 라이브러리 너무 좋고 훌륭하지만, embla-carousel
도 좋으니 한 번 맛 보는 것도 좋을 것 같다!
감사합니다!!