Carousel 구현하기

Sinf·2022년 5월 17일
2

고민의 흔적

목록 보기
19/38
post-thumbnail

Carousel 구현하기

Carousel은 슬라이드 쇼와 같은 형식을 가지며, 스크롤을 내리지 않고도 유저에게 다양한 정보를 제공할 때 사용한다.

씬프로드를 개발하면서, 이미지 여러 장을 캐러셀로 보여주기 위해 구현해봤다.

어떻게 구현할까?

  1. 이미지는 가로로 나열한다.
  2. 이미지를 담는 하나의 블록을 가지는데, overflow: hidden 속성을 가지고 있어서, 옆으로 넘어간 이미지의 경우 보이지 않도록 한다.
  3. 클릭, 혹은 시간이 지남에 따라 옆으로 넘어가도록 한다. 넘어갈 땐, transform 속성을 이용해 이동하는 모션을 준다.

코드로 확인하기

HTML 구조

컴포넌트의 기본적인 구조를 그린 코드는 다음과 같다.

// 화면에 보이는 부분
<div className="carousel" ref={container}>
  
  // 이미지 가로로 나열
  <div 
    className="carousel__slider"
    style={{
      width: `${images.length}00%`,
      transform: `translate3d(${index * -containerWidth}px, 0, 0)`,
    }}
    >
    { /* 받아온 images를 통해 이미지를 넣는다. (map을 이용) */ }
  </div>
  
  // 이전 이동 버튼
  <button onClick={() => handleClick("prev")} />

  // 다음 이동 버튼
  <button onClick={() => handleClick("next")} />
  
</div>

외부에 하나의 블록이 있고, 안에 좌우 버튼과 이미지를 가로로 나열한 블록이 있다.

캐러셀 스타일에,

<div 
  className="carousel__slider"
  style={{
    width: `${images.length}00%`,
    transform: `translate3d(${index * -containerWidth}px, 0, 0)`,
  }}
  >

width, transform 속성을 부여하는데, 이미지 만큼 너비를 가지도록 하고, 보고 싶은 이미지가 바뀔 때 (인덱스의 변경) 해당 슬라이더를 이동시키는 코드를 작성한 것이다.

상태 관리

const [index, setIndex] = useState<number>(0);
const [containerWidth, setContainerWidth] = useState<number>(0);
const container = useRef<HTMLDivElement>(null);

function handleClick(direction: "prev" | "next") {
  if (direction === "next") {
    return setIndex((x) => (x < images.length - 1 ? x + 1 : 0));
  }
  return setIndex((x) => (x > 0 ? x - 1 : images.length - 1));
}

const handleResize = () => {
  const { current } = container;

  if (!current) {
    return;
  }

  setContainerWidth(current.offsetWidth);
};

index는 현재 보여주는 이미지의 순서를 가진다.
containerWidth는 캐러셀을 담는 container의 너비를 저장한다. index가 변화함에 따라 이미지 순서를 넘기기 위해 사용한다.

handleClick은 이전, 다음 버튼을 클릭했을 때, index 값을 변경한다.

containeruseRef를 사용해, HTML DOM에 바로 접근할 수 있도록 한다.
화면의 크기가 변경될 때, 캐러셀을 담는 container 블록의 크기가 달라지기 때문에,
해당 DOM에 접근해 너비를 체크해야 한다. 해당 DOM의 너비를 체크해 containerWidth를 갱신한다.

추가 CSS

먼저, 캐러셀을 담는 블록은 넘치는 이미지를 가리기 위해 overflow: hidden을 사용한다.

.carousel {
  overflow: hidden;
}

슬라이더의 경우, flex 속성을 사용하고, flex-shrink: 0 속성을 부여한다. flex-shrink는 가로로 나열된 블록들을 다른 비율로 보이게 한다. MDN_flex-shirink

transition 속성을 부여해 transform으로 이미지가 변경될 때, 모션도 넣어준다.

.carousel__slider {
  display: flex;
  flex-shrink: 0;
  transition: transform 0.5s;
}

정리

캐러셀을 구현할 땐,

  1. 캐러셀을 담는 컨테이너 (외부 블록)
  2. 가로로 길게 이어지는 캐러셀 (데이터의 연속)
  3. 인덱스, 컨테이너 너비의 상태
  4. 인덱스 변화에 따라 캐러셀 변경

정도가 필요한 것 같다.

세부적으로 flex-shrink라는 속성, overflow:hidden 속성을 이용한다.

문제

이미지를 가져올 때, 원래 이미지 크기를 가져오고, 페이지에서 화면 비에 따라 변경된다. 이 때, container의 너비가 갱신되지 않는다. 그런 문제로 원래 넘어갈 크기만큼 넘어가지 않는 문제가 발생한다.

참고

profile
주니어 개발자입니다. 🚀

0개의 댓글