Frontend

Tailwind CSS에서 rem 단위를 px단위로 커스텀하기, 타입 에러 수정

코구리 2024. 8. 29. 20:36

프로젝트를 하면서 Tailwind CSS를 도입하기로 했다. 스타일 파일을 따로 만들거나 클래스 네임을 지정하지 않는 점은 참 간편한 것 같다. 근데 Tailwind에서는 rem단위를 기본적으로 지원하고 있었다.
 
https://tailwindcss.com/docs/margin

Margin - Tailwind CSS

Utilities for controlling an element's margin.

tailwindcss.com

 

 
이렇게 기본적으로 m-1 은 0.25rem 이고 m-2는 0.5rem 인 식이다. 반응형 구현에는 좋지만 정확하게 px 단위로 맞춰줘야 하는 경우도 있다. 특히 font-size도 일정 구간별로 지원하고 있어서 불편하다.
px 단위로 정확하게 표현하고 싶은 경우에는 arbitrary values라고 해서 대괄호 안에 넣어줘야 한다.

<h1 className="w-[320px] text-[32px]">gugi</h1>

 
이런식으로 표현해주면 된다.
이것보다 간편하게 해주기 위해서 기본 단위를 px로 커스텀해주기로 했다. 찾아보니 설정파일에서 theme를 extend 해주면 된다.
여기서 Array from 문법이 익숙하지 않아서 좀 찾아봤다.

 
const px0_10 = { ...Array.from(Array(11), (_, i) => `${i}px`) };
const px0_100 = { ...Array.from(Array(101), (_, i) => `${i}px`) };
const px0_200 = { ...Array.from(Array(201), (_, i) => `${i}px`) };
 

 
이 부분 쓰다가 갑자기 와이파이가 안되면서 글이 날라갔다 하하하 임시저장을 생활화하자^^..
MDN에서는 ' Array.from() 정적 메서드는 순회 가능 또는 유사 배열 객체에서 얕게 복사된 새로운 Array 인스턴스를 생성합니다.' 라고 말하고 있다. 즉 배열이 아닌 것을 배열로 만들어서 반환한다는 뜻이다.
이걸 활용해서 배열이 아닌 객체를 배열로 만들어 줄 수도 있을 것이다.
 
그리고 Array.from에는 세개의 매개변수를 사용할 수 있다. 사용법은 간단하다.

Array.from(arrayLike)
Array.from(arrayLike, mapFn)
Array.from(arrayLike, mapFn, thisArg)

 

  1. arrayLike
    이터러블 또는 유사배열 객체가 들어간다. 
  2. mapFn
    각 요소에 적용시킬 함수가 들어간다. 함수의 첫번째 매개변수로 element, 두번째 매개변수로 index가 들어간다.
  3. thisArg
    함수를 적용하면서 호출할 this값을 명시해줄 수 있다.

 
 
const px0_10 = { ...Array.from(Array(11), (_, i) => `${i}px`) };
 
그럼 내가 작성했던 코드를 다시보면 Array.from의 첫번째 매개변수로 Array(11)이라는 길이가 11인 유사배열이 들어가있다. 그리고 두번째 매개변수로 화살표 함수가 들어있는데 함수의 두번째 매개변수인 인덱스 i에 px을 붙여 각 요소마다 ${i}px을 반환하고 있다. 
이렇게 만들어진 진짜 배열을 ...인 spread 연산자로 분해해서 객체로 감싸준다. 
그러면 각 인덱스마다 px이 붙은 객체가 들어간다. 콘솔에 찍어보면 이렇다.

 
아무튼 이렇게 각 픽셀별로 값을 만들어준 셈이니까 불필요하게 많은 요소가 들어가면 메모리 낭비다.
그래서 스타일 속성 별로 사용할 구간을 세개 만들어주었다.
예를 들어 border는 커봤자 10px 이하로 들어갈테니 px0_10를 사용하면 되고 font-size는 px0_100을 사용하면 될것이다.
 
그래서 extend에 각 속성을 적용해줬다.

 
const px0_10 = {
  ...Array.from(Array(11), (_, i) => `${i}px`),
};
const px0_100 = {
  ...Array.from(Array(101), (_, i) => `${i}px`),
};
const px0_200 = {
  ...Array.from(Array(201), (_, i) => `${i}px`),
};
 
const config: Config = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}',
    './app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      borderWidth: px0_10,
      fontSize: px0_100,
      lineHeight: px0_100,
      minWidth: px0_200,
      minHeight: px0_200,
      spacing: px0_200,
      ...
    },
}
 

 

대충 엄청 긴 타입에러

그런데 작성한 속성에서 타입에러가 나고 있었다. 
그래서 에러난 부분에 커서를 올려 자세히 보니까 자동으로 설정된 ResolvableTo라는 타입이 눈에 띄어서 ctrl 클릭해서 들어가봤다.

 

 
그랬더니 이런식으로  ThemeConfig라는 인터페이스 내에 테마의 속성이 모두 정의되어있는 것을 볼 수 있었다. 그래서 borderWidth 에서 사용되고 있는 ResolvableTo 의 타입은 다음과 같다. 보니까 제네릭 타입으로 T를 쓰고 있고, T가 그대로 반환되거나 함수일지라도 T가 반환되어야 했다.
하지만 배열로 만든 것을 spread 연산자로 해체해서 number : string 타입의 요소로 만들어준 것을 인지하지 못하는 것 같다. T가 아닌 다른 타입으로 나온 것이다. 근데 사실 왜 인지를 못하는지 원리를 모르겠다.. 찾아봐도 잘이해가 안돼서 좀더 확인해봐야 할 것 같다.
암튼 그래서 U를 제네릭 타입으로 추가해서 수정해줬더니 에러가 사라졌다.
 
config.d.ts

수정전
수정후

 

말끔히 제거된 에러

 
이렇게 해서 설정이 완료되었다.

 
<h1 className="text-32">gugi</h1>
 

 
이제 이런식으로 숫자만 쓰면 px단위로 잘 적용된다!
 
 
Ref
https://fe-developers.kakaoent.com/2022/220303-tailwind-tips/

Tailwind CSS 사용기 | 카카오엔터테인먼트 FE 기술블로그

서종만(coze) 생산성을 높이는 일을 좋아합니다. 오늘 1분 걸린 작업이 내일 30초 걸리는 방법을 발견하면 기뻐합니다.

fe-developers.kakaoent.com

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from

Array.from() - JavaScript | MDN

The Array.from() static method creates a new, shallow-copied Array instance from an iterable or array-like object.

developer.mozilla.org