Tailwind CSS vs CSS Modules — 프로덕션에서 내가 사용하는 방식
요약
Tailwind CSS와 CSS Modules의 실무 활용 방식을 비교하며, 프로젝트의 성격에 따른 적절한 스타일링 도구 선택 기준을 제시합니다. 마케팅 사이트의 빠른 반복 작업에는 Tailwind가, 브랜드 시스템 상속이나 정교한 디자인 핸드오프에는 CSS Modules가 유리함을 설명합니다.
핵심 포인트
- Tailwind CSS는 JSX 내 콜로케이션이 뛰어나 개발 속도가 빠름
- CSS Modules는 디자인 토큰 및 브랜드 시스템 상속에 유리함
- 복잡한 레이아웃이나 화이트 라벨링 요구사항에는 CSS Modules가 적합
- 도구 선택 시 개발 생산성과 디자이너와의 협업 효율을 고려해야 함
모든 새로운 프로젝트는 동일한 논쟁을 불러일으킵니다: 유틸리티 클래스(utility classes)인가, 아니면 스코프가 지정된 CSS 파일(scoped CSS files)인가? 나는 safdarali.in을 포함한 대부분의 Next.js 마케팅 사이트에는 Tailwind CSS를 배포하지만, 디자인 토큰(design tokens), 애니메이션, 또는 디자이너와의 핸드오프(handoff)가 실제 스타일시트를 요구할 때는 여전히 CSS Modules를 사용합니다. 이 tailwind vs css modules 비교는 두 방식 모두에서 동일한 프로필 카드(profile card)를 사용하여, 서로 다른 UI가 아닌 사용성(ergonomics)을 판단할 수 있도록 합니다.
동일한 컴포넌트 — Tailwind 버전
// components/ProfileCard.tsx
type Props = { name: string; role: string; avatarUrl: string };
...
컨텍스트 스위칭(context switch)이 없습니다 — 레이아웃, 색상, 다크 모드(dark mode)가 JSX에 함께 위치합니다. 혼자 반복 작업(iterate)을 할 때는 콜로케이션(Colocation)이 매우 뛰어납니다. 복잡한 그리드(grids)에서는 클래스 문자열이 길어지는데, 저는 200자짜리 한 줄을 만드는 대신 더 작은 컴포넌트로 분리합니다.
지난 분기 벵갈루루(Bengaluru)의 한 스타트업 랜딩 페이지 작업 중, 디자이너가 한 스프린트(sprint) 동안 카드 패딩(padding)을 세 번 변경했습니다. Tailwind를 사용했기에 저는 별도의 CSS 파일을 찾아 헤맬 필요 없이, 카피(copy) 변경과 동일한 PR에서 유틸리티를 조정했습니다. 마케팅용으로는 이러한 속도 때문에 유틸리티를 기본값으로 사용합니다. 트레이드오프(tradeoff)는 코드 리뷰 시의 가독성입니다. 리뷰어는 일반적인 클래스 이름을 알고 있거나 프리뷰 배포(preview deploys)에 의존해야 합니다.
동일한 컴포넌트 — CSS Modules 버전
// components/ProfileCard.module.css
.card {
display: flex;
...
// components/ProfileCard.tsx
import styles from "./ProfileCard.module.css";
...
Figma 스펙을 읽는 디자이너들은 종로 종종 이 방식을 선호합니다. 클래스 이름이 검색 가능한 스타일시트에 매핑되기 때문입니다. 테마 변수(Theme variables)는 dark: 접두사를 중복해서 사용하는 대신 하나의 CSS 파일에 존재합니다.
CSS Modules는 SCSS나 일반 CSS로 문서화된 브랜드 시스템을 상속받을 때 빛을 발합니다. 예전에 모든 간격 토큰(spacing token)이 변수로 정의된 프로젝트에 합류한 적이 있는데, 이를 Tailwind로 다시 쓰는 것은 사용자에게 아무런 이득 없이 몇 주가 걸리는 작업이었을 것입니다. 모듈(Modules)을 사용하면 새로운 React 컴포넌트를 배포하면서도 기존의 레거시 스타일(legacy styles)을 스코프가 지정된 클래스 이름으로 감쌀 수 있습니다.
8가지 기준 비교 테이블
| 기준 | Tailwind CSS | CSS Modules |
|---|---|---|
| JSX와의 결합 (Colocation) | 매우 우수 | 파일 분리 |
| ... |
Tailwind가 불리한 경우
Tailwind가 약한 것은 아닙니다. 다만 스타일시트 자체가 제품인 경우에는 잘못된 도구가 될 수 있습니다. 긴 형태의 에디토리얼 레이아웃(editorial layouts), 인쇄용 인보이스(printable invoices), 그리고 각 테넌트(tenant)가 서로 다른 CSS 파일을 배포하는 화이트 라벨 테마(white-label themes)의 경우, 수천 개의 임의적인 유틸리티 문자열(utility strings)을 사용하는 것보다 모듈(modules)이나 글로벌 레이어(global layers)를 사용하는 것이 논리적으로 파악하기 더 쉽습니다.
키프레임 중심의 애니메이션 (Keyframe-heavy animations) — 순차적 등장(staggered reveals)이나 복잡한 호버 체인(hover chains)은 모듈 파일에서 더 읽기 좋습니다. 인쇄용 스타일시트 (Print stylesheets) — Tailwind로도 가능하지만, CSS가 더 명확합니다. SCSS 변수로 이미 문서화된 레거시 디자인 시스템 (Legacy design systems) — 이를 유틸리티로 다시 쓰는 것은 낭비입니다. 고도로 맞춤화된 아트 디렉션 페이지 (Highly bespoke art-directed pages) — 모든 섹션이 토큰 스케일(token scale)에 없는 고유한 간격을 가진 경우, 임의의 값(arbitrary values)과 싸우는 것이 CSS를 작성하는 것보다 더 느립니다.
/* ProfileCard.module.css — Tailwind가 대응하기 까다로운 애니메이션 */
@keyframes riseIn {
from { opacity: 0; transform: translateY(12px); }
...
스타일 마이그레이션 — 전과 후
// 이전 — 프로덕션으로 유출된 글로벌 CSS
.button {
background: blue;
...
Tailwind는 다른 방식으로 글로벌 유출(global leakage)을 방지합니다. 유틸리티는 원자적(atomic)이기 때문입니다. 두 방식 모두 2018년 Create React App 프로젝트에서 사용되던 구조화되지 않은 글로벌 CSS보다는 낫습니다.
클라이언트 사이트에서 내가 사용하는 하이브리드 방식
실제 프로덕션에서는 다음과 같이 사용합니다: 레이아웃, 간격(spacing), 타이포그래피(typography), 반응형 그리드(responsive grids)에는 Tailwind를 사용합니다. 애니메이션, 드문 서드파티 오버라이드(third-party overrides), 그리고 인쇄 규칙에는 CSS Modules(또는 단일 globals.css)를 사용합니다. 최근 진행한 마케팅 사이트 리빌딩에서 이러한 분리 방식을 통해 Lighthouse CSS 페이로드(payload)를 작게 유지하면서도, 디자이너들이 히어로 애니메이션(hero animation)을 위한 모듈을 사용할 수 있게 했습니다. 자세한 내용은 성능 사례 연구를 참조하세요.
나의 프로덕션 설정
기본 스택: Next.js + TypeScript strict + Tailwind + 조건부 클래스를 위한 cn() 헬퍼. 컴포넌트에 약 15줄 이상의 커스텀 CSS가 쌓이면 기능(feature) 폴더별로 모듈을 추가합니다. 현재 직장에서는 리셋(resets)을 제외한 새로운 글로벌 셀렉터(global selectors) 사용을 금지하고 있습니다.
어떤 선택을 하더라도 잘못된 컴포넌트 아키텍처(component architecture) 문제를 해결해주지는 않습니다. 제가 스타일을 기능(features)과 함께 배치(colocate)하는 방식은 Next.js 폴더 구조 가이드를 참조하세요.
또한 유틸리티(utilities)를 사용하는 팀에서는 Tailwind class sorter 플러그인과 함께 Prettier를 실행합니다. 일관된 순서는 긴 클래스 문자열(class strings)의 diff를 깔끔하게 만들어 줍니다. 대신 CSS Module 프로젝트에서는 중첩(nesting)과 변수 명명(variable naming)을 위해 stylelint를 사용합니다.
핵심 요약
속도를 원한다면 Tailwind, 복잡성을 다룬다면 CSS Modules. 특정 신념(religion)에 따르지 말고 컴포넌트별로 선택하세요. 동일한 카드라도 두 가지 구현 방식이 가능합니다. 6개월 뒤에 실제로 유지보수하게 될 파일을 선택하십시오.
제가 인도의 주니어들에게 주는 면접 팁은 다음과 같습니다: 두 답변 모두 그 자체로는 틀리지 않습니다. 팀이 이미 무엇을 사용하고 있는지, 디자이너와 매일 협업하는지, 그리고 해당 페이지가 마케팅용인지 아니면 오래 지속되는 대시보드(dashboard)인지 물어보세요. 툴체인(toolchain)을 Twitter 투표가 아닌, 전달 주기(delivery cadence)에 맞추십시오.
이 글이 도움이 되었다면
저는 여가 시간에 이와 같은 무료 튜토리얼과 글을 게시하며, 가이드에 유료 결제 장벽(paywall)을 두지 않습니다. 만약 이 글이 여러분의 시행착오 시간을 줄여주었다면, 작업을 후원하실 수 있습니다:
관련 읽을거리
safarali.in의 더 많은 가이드 — 동일한 저자가 작성하였으며, 프로덕션(production)에 초점을 맞추고 있습니다.
-
[
Zustand vs Redux Toolkit — 2026년에는 어떤 상태 관리자(State Manager)를 사용해야 할까?
Zustand vs Redux Toolkit 2026 — 비교 표, 코드 비교, 번들 크기(bundle size), 그리고 프로덕션(production) 권장 사항.
2026년 6월 · 기사 읽기 →
-
[
무료 온라인 비디오 썸네일 생성기 — 업로드 불필요
무료 온라인 비디오 썸네일 생성기 — 업로드 없이 비디오에서 프레임 추출. 브라우저 기반, 워터마크 없음, MP4 워크플로우를 통한 YouTube 썸네일 제작.
2026년 6월 · 기사 읽기 →
](https://safdarali.in/blog/free-video-thumbnail-generator-online-no-upload)
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기