
Tailwind 스타일이 적용 안 될 때 체크해야 할 5가지 (The Case of Missing Styles)
분명히 클래스를 적었는데 화면은 그대로다? 개발자 도구엔 클래스가 있는데 스타일이 없다? Tailwind 실종 사건 수사 일지.

분명히 클래스를 적었는데 화면은 그대로다? 개발자 도구엔 클래스가 있는데 스타일이 없다? Tailwind 실종 사건 수사 일지.
클래스 이름 짓기 지치셨나요? HTML 안에 CSS를 직접 쓰는 기괴한 방식이 왜 전 세계 프론트엔드 표준이 되었는지 파헤쳐봤습니다.

시각 장애인, 마우스가 고장 난 사용자, 그리고 미래의 나를 위한 배려. `alt` 태그 하나가 만드는 큰 차이.

안드로이드는 Xcode보다 낫다고요? Gradle 지옥에 빠져보면 그 말이 쏙 들어갈 겁니다. minSdkVersion 충돌, Multidex 에러, Namespace 변경(Gradle 8.0), JDK 버전 문제, 그리고 의존성 트리 분석까지 완벽하게 해결해 봅니다.

서버에서 잘 오던 데이터가 갑자기 앱을 죽입니다. 'type Null is not a subtype of type String' 에러의 원인과, 안전한 JSON 파싱을 위한 Null Safety 전략을 정리해봤습니다.

신규 프로젝트 마감 전날, 저는 기이한 현상을 목격했습니다.
분명히 버튼에 bg-blue-500을 줬는데, 버튼은 여전히 투명했습니다.
<button className={`bg-${color}-500 text-white`}>
Click Me
</button>
개발자 도구(F12)를 켜서 확인해 보니, button 태그에 클래스는 정확히 들어있었습니다.
하지만 Computed 탭이나 Styles 탭을 아무리 뒤져봐도 background-color 속성은 없었죠.
마치 유령처럼, 이름만 있고 실체는 없는 클래스였습니다.
이 수사 기록은 그날 밤 제가 범인(버그)을 잡기 위해 파헤친 5가지 용의자 리스트입니다.
Tailwind는 런타임에 스타일을 만드는 게 아니라, 빌드 타임에 파일을 스캔해서 스타일을 만듭니다.
즉, PurgeCSS(JIT 컴파일러)가 소스 코드를 텍스트로 읽어서 "어, bg-blue-500이라는 문자열이 있네?" 하면 CSS를 생성합니다.
문제의 코드를 다시 봅시다.
// ❌ 범인은 바로 이 녀석
const color = 'blue';
<button className={`bg-${color}-500`}>Click</button>
컴파일러는 코드를 실행해보지 않습니다. 그냥 텍스트로만 봅니다.
컴파일러 눈에는 bg-와 -500은 보이지만, bg-blue-500이라는 완성된 문자열은 보이지 않습니다.
그래서 "아, 이 클래스는 안 쓰는구나" 하고 CSS 파일에서 제외시켜 버립니다.
// ✅ 전체 문자열을 매핑해서 사용
const colorVariants = {
blue: 'bg-blue-500',
red: 'bg-red-500',
green: 'bg-green-500'
};
<button className={colorVariants[color]}>Click</button>
이제 컴파일러는 bg-blue-500을 명확하게 볼 수 있습니다.
content 설정 누락 (공범)tailwind.config.js 파일의 content 배열은 컴파일러의 "수색 범위"입니다.
여기에 파일 경로가 빠져 있다면, Tailwind는 그 파일을 쳐다보지도 않습니다.
// tailwind.config.js
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
// ⚠️ 혹시 새로운 폴더(components/ui 등)를 만들고 여기 추가 안 했나요?
],
// ...
}
제 경우, 모노레포 구조에서 공유 UI 패키지의 경로를 content에 추가하지 않아서 발생한 적이 있습니다.
새로운 디렉토리를 만들었다면 꼭 수색 영장(content)에 추가해주세요.
클래스는 적용됐는데 다른 스타일에 덮어씌워진 경우입니다. 특히 기존 CSS 라이브러리(Bootstrap 등)와 함께 쓸 때 자주 발생합니다.
개발자 도구에서 스타일이 취소선(strike-through)으로 그어져 있다면 이 경우입니다.
해결책 1:!important 사용 (비추천)
<div className="bg-red-500!" /> {/* Tailwind 3.x 문법 */}
해결책 2: Tailwind 우선순위 높이기
CSS 파일에서 @tailwind base; 등이 다른 스타일보다 아래에 오도록 하거나, ID 선택자 등으로 감싸서 점수를 높이세요.
가끔은 그냥 컴퓨터가 멍청해서 발생합니다. 설정을 바꿨는데도 반영이 안 된다면? JIT 컴파일러가 이전 결과를 캐시하고 있을 수 있습니다.
해결책: 껐다 켜기 & 캐시 삭제npm run dev 다시 실행).next 폴더나 node_modules/.cache 폴더 삭제"껐다 켜니까 되는데요?"는 개발계의 영원한 진리입니다.
만약 동적 클래스를 꼭 써야 한다면? (예: CMS에서 색상을 받아오는 경우)
safelist 옵션을 사용하면 컴파일러에게 "이건 무조건 남겨둬"라고 명령할 수 있습니다.
// tailwind.config.js
module.exports = {
safelist: [
'bg-red-500',
'text-3xl',
{
pattern: /bg-(red|green|blue)-(400|500)/, // 정규식도 가능!
},
],
// ...
}
하지만 이 방법은 CSS 파일 크기를 키우므로 꼭 필요한 경우에만 사용하세요.
클래스 이름에 /, [, ] 같은 특수문자가 들어갈 때 발생합니다.
예를 들어 w-1/2는 괜찮지만, 커스텀 값 w-[50%] 같은 걸 쓸 때 가끔 문제가 됩니다.
HTML 클래스 속성에서는 괜찮지만, document.querySelector 같은 걸로 찾을 때는 이스케이프가 필요합니다.
하지만 React 컴포넌트 내부라면 보통은 문제가 안 됩니다. 다만, 오타가 없는지 확인하세요. 의외로 text-blud-500 같은 오타가 범인일 때가 많습니다.
제 사건의 범인은 역시 용의자 1번(동적 클래스 문자열 조합)이었습니다.
bg-${props.color}-500을 clsx 라이브러리와 객체 매핑으로 바꾸자마자 파란색 버튼이 영롱하게 빛났습니다.
여러분도 스타일이 실종됐다면, 당황하지 말고 이 5가지 용의자를 차례로 심문해 보세요. 범인은 반드시 이 안에 있습니다.
제가 겪었던 황당한 사고입니다. 로컬에서는 잘 나오는데, 프로덕션 배포만 하면 스타일이 깨지는 겁니다.
원인: CI/CD 파이프라인에서 NODE_ENV=production으로 빌드할 때, Tailwind가 불필요한 클래스를 너무 공격적으로 제거(Purge)했습니다.
이유는, 제가 백엔드에서 API로 받아온 데이터를 클래스 이름으로 쓰고 있었기 때문입니다.
status가 active면 text-green-500, inactive면 text-gray-500.
이게 DB에만 있고 코드에는 없으니까, 배포 빌드 때 싹 날아간 거죠.
교훈: DB 데이터로 스타일링 할 때는 반드시 SafeList를 쓰거나, 프론트엔드 코드 내에 map 객체를 만들어야 합니다.