이번에 tailwind로 작업하다 문제가 생겼는데 입력마다 textarea 의 높이를 텍스트가 들어올 때 마다 움직이게 하기 위해 height 을 동적으로 주고 싶었습니다.
하지만 tailwind는 미리 정해진 유틸리티 클래스 모음으로 1px 단위까지 디테일하게 설정할 필요는 없을거라 생각했습니다.
// use tailwind + normal style
<input ...
className="text-2xl w-full ..."
style= {{height: heightState}} >
`style: height` 처럼 기존의 CSS로 설정하면 되지만 하나의 tailwind 스타일로 통일하고 싶었습니다.
// use tailwind
const getAutoHeight = (heightState) => `h-[${heightState}px]`
<input ...
className={`${getAutoHeight} text-2xl w-full ...`}>
이 방법은 tailwind의 특징을 해치지만.. 폭 넓게 사용가능한 arbitrary value 로 값을 동적으로 받으려고 했지만 적용되지 않았는데..
그 이유는 tailwind는 완벽한 클래스 이름이 아니면 인식하지 못하기 때문입니다.
빌드할 때 완벽한 이름 (ex. bg-gray-400
) 이 아닌
불완전한 이름(ex. bg-gray-${weight}
) 과 같은 어떤 값이 들어올지 모르는 변수는 tailwind는 추적하지 못합니다.
tailwind는 프로덕션 빌드에서 사용하지 않는 스타일을 제거해 최종 CSS 파일을 더 작고 성능 좋게 만드는 PurgeCSS가 내장되어 있습니다.
tailwind에서 정한 규칙에 따라 완벽한 클래스 네임이 아닌 bg-gray-${weight} 와 같은 불완전한 이름들은 전부 제외합니다.
하지만 이런 불완전한 것들도 세이프하는 방법이 있습니다.
safelist 설정으로 필요한 클래스 안전하게 지키기
이때, safelist를 활용하면 빌드할 때 추적하지 못한 불완전한 이름을 미리 등록해 사용할 수 있습니다.
이름이 정말 직관적인데 이 배열 안에 들어간 값들은 빌드 시 지우지 않는다는 것을 보장합니다.
즉, 런타임 환경에서 변수로 인해 바뀌는 클래스 네임들도 사용할 수 있다는 말이죠!
// tailwind.config.js
module.exports = {
safelist: [
"choonsik-1",
"choonsik-2",
// "choonsik-[0~100]" 까지 넣는 함수
...choonsik_0_100,
{ pattern: /choonsik-\d+/ },
{
pattern: /text-(blue|green|indigo|pink|orange|rose)-(600|400)/,
variants: ['hover'],
},
... ,
]
}
적용 방법은 tailwind.config.js 파일의 safelist의 배열 안에 클래스네임을 넣으면 됩니다.
문자열, 함수, 객체 안 pattern 속성의 정규표현식을 사용하여 적용합니다.
하지만, safelist는 tailwind style을 적용하는 무적같은 방법 같지만 안쓰일 수도 있는 classname까지도 전부 컴파일할 수 있어 빌드 크기가 커질 수도 있기 때문에 사용에 유의해야합니다.
마치면서
Tailwind의 기본적인 기능들 말고도 Safelist나 Arbitrary Value에 대해서 알게 됐는데 유틸리티 클래스의 한계점, 장점들을 구분할 수 있게 됐습니다.
만약에 픽셀단위로 0~1000 정도의 많은 클래스네임을 safelist하는게 맞을까?
굳이 tailwind로 그 큰 유틸리티 클래스를 만들어서 쓰지 않고 기본 CSS를 활용해서 구성하는게 더 효율적이지 않을까?
일관성 때문에 고민했었는데 상황에 따라 다르겠지만 일단, 통일해보고 나서 문제있으면 바꾸는게 낫지 않을까 싶습니다.