[Tailwind] 반응형 breakpoint에 따른 className 동적 생성 방법

박기영·2023년 5월 8일
0

Tailwind

목록 보기
10/10

TailwindCSS는 breakpoint 사용이 매우 간편하기 때문에 반응형 UI를 간편하게 생성할 수 있다.
필자는 이를 활용하여 캐러셀 슬라이드를 만들고 있었다.
화면 크기에 따라 이미지 크기도 변경해야했기 때문에, breakpoint와 함께 width값을 동적으로 생성하는 것이 목표였는데, 너무 어려웠다.
TailwindCSS로만 구현하려다 보니까 생기는 문제인건지, 필자의 실력 문제인건지 모르겠지만
어떻게든 TailwindCSS로만 UI를 마무리 짓고 싶어서, 여러 자료를 찾아봤다.
그나마 효과가 있었던 해결 방법에 대해 적어놓고자 한다.

tailwindcss : "^3.1.8"

문제 상황

말로만 설명하면 도대체 뭔 상황인지 이해가 되지 않기 때문에, 코드를 직접 보면서 이야기를 하겠습니다.

// ... //

export const imgSize = {
  basic: 300,
  sm2: 400,
  sm: 600,
  xl: 800,
};

function Carousel() {
  // ... //

  const copiedArr = [
    postData.file[postData.file.length - 1],
    ...postData.file,
    postData.file[0],
  ];

  // ... //

  const dynamicCarouselSize = {
    basic: `w-[${imgSize.basic}px] h-[${imgSize.basic}px]`,
    sm2: `2sm:w-[${imgSize.sm2}px] 2sm:h-[${imgSize.sm2}px]`,
    sm: `sm:w-[${imgSize.sm}px] sm:h-[${imgSize.sm}px]`,
    xl: `xl:w-[${imgSize.xl}px] xl:h-[${imgSize.xl}px]`,
  };

  const dynamicSlideSize = {
    basic: `w-[${imgSize.basic * copiedArr.length}px]`,
    sm2: `2sm:w-[${imgSize.sm2 * copiedArr.length}px]`,
    sm: `sm:w-[${imgSize.sm * copiedArr.length}px]`,
    xl: `xl:w-[${imgSize.xl * copiedArr.length}px]`,
  };

  return (
    <div
      className={`mb-8 shadow-xl ${dynamicCarouselSize.basic} overflow-hidden relative ${dynamicCarouselSize.sm2} ${dynamicCarouselSize.sm} ${dynamicCarouselSize.xl}`}
    >
      <div
        className={`flex flex-nowrap ${dynamicSlideSize.basic} ${dynamicSlideSize.sm2} ${dynamicSlideSize.sm} ${dynamicSlideSize.xl}`}
        style={{
          transition: "all 500ms ease-in-out",
          transform: `translateX(${
            -1 * ((100 / copiedArr.length) * slideIndex)
          }%)`,
        }}
        ref={slideRef}
      >
        // ... //
      </div>
      
      // ... //
      
    </div>
  );
}

export default Carousel;

dynamicCarouselSize, dynamicSlideSize 객체에 변수로 값을 설정하고
className에 넣어주는 것이 목표였다.

또한, dynamicSlideSize는 이미지의 개수에 따라 동적으로 변경되는 값이기 때문에,
반드시 * 연산이 필요한 상황이었다.

TailwindCSS는 임의의 값(arbitrary value)를 사용하기 위해 대괄호(square bracket)을 사용한다.
따라서, 코드만 보면 큰 문제가 없어보인다.

그러나, 저 코드는 적용이 안된다.

참고 이미지

개발자 도구에서는 확인이 된다. 하지만, 적.용.이 안된다 ㅠㅠ

이유

참고 이미지

TailwindCSS 공식 docs에는 위와 같은 경고가 적혀있다.
className을 동적으로 생성하기 위해서 props를 사용하지마라.

참고 이미지

그 대신, 위와 같은 방법을 사용하기를 권장한다.
정적(static) classNames를 사용하라고 한다.
쉽게 생각하자면..
className에서 만들어서 쓰려고 하지말고, 미리 만들어서 className에 가져오라는 것이다.

아무튼, 이러한 이유로 인해서 필자의 코드가 작동하지 않았던 것이다.
분명히 미리 만들어서 가져오기는 했는데, 여전히 동적으로 className을 생성하고 있었기 때문이다.

// 신기하게도 이 부분은 잘된다.
const dynamicCarouselSize = {
  basic: `w-[${imgSize.basic}px] h-[${imgSize.basic}px]`,
  sm2: `2sm:w-[${imgSize.sm2}px] 2sm:h-[${imgSize.sm2}px]`,
  sm: `sm:w-[${imgSize.sm}px] sm:h-[${imgSize.sm}px]`,
  xl: `xl:w-[${imgSize.xl}px] xl:h-[${imgSize.xl}px]`,
};

// 문제가 되는 부분(아마도)
const dynamicSlideSize = {
  basic: `w-[${imgSize.basic * copiedArr.length}px]`,
  sm2: `2sm:w-[${imgSize.sm2 * copiedArr.length}px]`,
  sm: `sm:w-[${imgSize.sm * copiedArr.length}px]`,
  xl: `xl:w-[${imgSize.xl * copiedArr.length}px]`,
};

동적으로 생성된다고 판단되는 곳은 위 코드이다.
그런데, dynamicCarouselSize는 잘 작동한다.
흠...그러면 * 연산 때문에 동적으로 생성되는 걸로 간주되는 걸까?
이 의문을 기점으로 필자가 가장 먼저 취한 방법은 동적으로 연산되는 부분을 줄이는 것이었다.

해결 방법

const dynamicSize = {
  basic: imgSize.basic * copiedArr.length,
  sm2: imgSize.sm2 * copiedArr.length,
  sm: imgSize.sm * copiedArr.length,
  xl: imgSize.xl * copiedArr.length,
};

const dynamicSlideSize = {
  basic: `w-[${dynamicSize.basic}px]`,
  sm2: `2sm:w-[${dynamicSize.sm2}px]`,
  sm: `sm:w-[${dynamicSize.sm}px]`,
  xl: `xl:w-[${dynamicSize.xl}px]`,
};

* 연산을 줄이고, 연산이 완료된 값을 가져와서 대괄호에 넣어줬다.
이제 정상 작동이 된다!

대괄호 안에 직접적인 연산이 들어가지만 않으면 되는 것 같다..!
하긴 대괄호 안에 123px 입력하면 제대로 작동하니까 당연한 원리였던건가???

참고 자료

TailwindCSS 공식 docs
arthur님 블로그
TailwindCSS github discussions

profile
나를 믿는 사람들을, 실망시키지 않도록

2개의 댓글

comment-user-thumbnail
2023년 5월 8일

이것도 모르냐?

1개의 답글