공부/Html & CSS

Tailwind CSS, 제대로 쓰려면 알아야 할 철학과 원칙 파헤치기

dev_jiwonpark 2025. 12. 9. 22:50

예전에 같이 개발을 공부하던 팀원들과 프로젝트를 만들때 속도감 있게 개발하자! 가 중요한 우선순위여서 나는 전통적으로 CSS 파일을 관리하기 보다 Tailwind CSS를 선택해서 프론트 개발을 했었다.

그때의 나는 단지 Tailwind 가 쉽게 UI 개발을 도와주는 프레임워크라고 생각해 선택해서 사용했던 것 같다.

그런데 프로젝트의 규모가 커지면서 기능들이 많아지고 구현해야할 UI 가 늘어나면서 점점 클래스가 길어지기 시작했다..

결국 단순한 UI 하나를 수정하려면 긴~ 클래스 하나하나 살펴보면서 수정해야했다. 

그러면서 Tailwind에 대한 나의 결론은 " 온보딩 하기에는 쉬우나 규모가 큰 프로젝트에는 못쓰겠구만! " 이였다.

그런데 이번에 개인적으로 사이드 프로젝트를 개발하면서 역시나 같은 마인드로 .. CSS에 큰 신경을 쓰고 싶지않아! Tailwind를 선택해서 개발을 하던중 .. 나는 Tailwind가 무엇이고 왜 개발되었고 철학이 무엇인지에 대해서 전혀 궁금해하지 않으면서 사용하고 있었다는 생각이 들었다. 그래서 이번에 Tailwind의 철학과 다른 CSS 프레임워크와 어떤 점이 다른지에 대해서 공부한 내용을 정리해 보려고 한다.


 

우선 Tailwind 공식 문서를 살펴보면 Tailwind의 핵심 철학은 "Utility-First" 라고 한다. 

https://v1.tailwindcss.com/docs/utility-first

 

Styling with utility classes - Core concepts

Building complex components from a constrained set of primitive utilities.

tailwindcss.com

그럼 Tailwind에서 말하는 Utility-First란 무엇일까??

 

이 Utility-First를 이해하려면 기존 CSS 방식의 불편함을 알아야한다.

전통적인 CSS 작성 방식은 웹 프론트엔드 개발자라면 다들 경험해봤을것이다.

.card-wrapper { }
.card-wrapper-inner { }
.card-wrapper-inner-content { }
.card-wrapper-inner-content-title { }

위와 같이 CSS 클래스 이름을 짓다가 하루가 가버린다..

depth가 깊어지면 깊어질수록 클래스 이름이 길어져 버리고.. 수정하려고 하면 찾느라 시간 낭비하고 

그러다가 프로젝트가 커지면 CSS파일이 n천 줄이 돌파하게 되고 CSS 수정할 엄두가 안나게 된다.

 

하지만 우리는 웹 개발을 처음 배울때 "HTML 은 구조, CSS는 스타일, JS는 동작" 이렇게 구분지어서 배우게 되는데

Tailwind는 이걸 정면으로 반박한다.

 

" 어짜피 버튼 HTML 수정하면 버튼 CSS도 같이 수정하는데 그럼 처음부터 같이 두는게 낫지 않냐? " 이거다.

생각해보면 맞는 말이긴 하다.

 

버튼 컴포넌트를 수정할 때 
1. Button.tsx 열고
2. button.css 찾아서 열고
3. 둘 다 수정하고
4. 혹시 다른 데 영향 없나 확인하고... 

이렇게 단계를 나눠서 개발을 할바에 Tailwind는 이 과정을 하나로 줄이자! 라는 것이다.

Button.tsx 딱 하나만 열면 구조와 스타일이 한눈에 다 보이기 때문이다.

 

Tailwind 공식 문서에 이런 문장이 있다.

Building complex components from a constrained set of primitive utilities.

직역하면 "제약된 기본 유틸리티 세트로 복잡한 컴포넌트를 만든다" 라는 말인데

무슨 말인지 하나씩 뜯어보자!

 

primitive utilities (기본 유틸리티)

우선 Tailwind의 클래스들은 하나의 역할만 한다. 그래서 원시적인, 기본적인 유틸리티라는 것이다.
 
flex        → display: flex 하나만
p-4         → padding: 16px 하나만
text-white  → color: white 하나만
rounded-lg  → border-radius 하나만
 
클래스 하나하나가 레고 블록이라고 생각하면 편하다.
각 블록은 단순하지만 조합하면 뭐든 만들수 있기 때문이다.
 

constrained set (제약된 세트)

Tailwind 클래스를 사용하려고 할때 아무 값이나 쓸수 있는 것이 아니다.

Tailwind는 미리 정해둔 값만 제공한다.

/* spacing 예시 */
p-1 → 4px
p-2 → 8px
p-3 → 12px
p-4 → 16px
p-5 → 20px

 

4px 단위로 spacing이 나눠져있고 10px, 13px은 기본적으로 제공되지 않는다.

원래 웹 개발을 할때 디자이너 없이 개발하다 보면 아래와 같이 일관성 없는 CSS를 작성하곤 한다.

.box1 { padding: 12px; }
.box2 { padding: 13px; }
.box3 { padding: 14px; }
.box4 { padding: 17px; }

 

하지만 Tailwind는 이걸 차단한다! 정해진 값만 쓰게 하니까 자연스럽게 일관성이 생기는 것이다.

 

building complex components (복잡한 컴포넌트 만들기)

 

따라서 단순한 클래스들을 조합해서 복합한 UI를 만들수가 있게된다.

<!-- 기본 블록들 -->
flex, items-center, gap-2, px-4, py-2, 
bg-blue-500, hover:bg-blue-600, 
text-white, font-medium, rounded-lg

<!-- 조합하면 버튼 완성 -->
<button class="flex items-center gap-2 px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white font-medium rounded-lg">
  <Icon />
  버튼
</button>

 

이게 바로 " 디자인 토큰 " 개념이기도 한데

미리 정해둔 값(토큰)을 사용하게 되면 UI 일관성이 자연스럽게 유지된다.

 

그래서 Tailwind의 철학을 정리하면 어떻게 되냐!

Tailwind는 "유틸리티 퍼스트" 철학을 기반으로 한다.

핵심은 CSS 클래스 이름을 추상화해서, 개발자가 CSS를 직접 작성하는 대신 미리 정의된 클래스를 조합하는 방식이라는 것이다.

.card-wrapper-inner-content 같은 이름 고민은 이제 그만하고 flex, p-4, bg-blue-500 같이 의미가 명확한 CSS 클래스를 사용하는 것이다.

그리고 HTML과 CSS를 억지로 나누지 않고 한곳에서 구조 & 스타일을 같이보면 개발속도가 훨씬 빨라지는 것이다.

또한 정해진 디자인 토큰을 사용하면 UI 일관성은 자동으로 따라오게 된다.

누가 봐도 이해하기 쉬운 코드 & 수정하기 쉬운 코드가 되는 것이다. 

 

한줄로 요약하자면 아래와 같다.

"미리 정의된 클래스를 조합해서 스타일링하고, 일관성을 유지하면서 빠르게 UI를 개발하고, 가독성 높은 코드로 유지보수를 쉽게 만든다."

 

그렇지만! 이 철학이 제대로 작동하려면 몇가지 전제 조건들이 있다.

Tailwind가 좋은건 알겠는데 아무 프로젝트에나 쓰게된다면..? 오히려 개발이 더 힘들어 질수 있다..

https://evilmartians.com/chronicles/5-best-practices-for-preventing-chaos-in-tailwind-css

 

5 best practices for preventing chaos in Tailwind CSS—Martian Chronicles, Evil Martians’ team blog

Tailwind CSS has become a very popular CSS framework, and it can speed up development. But using it without proper caution can add mayhem to your code. Learn best practices to avoid getting swept away!

evilmartians.com

위 글에서 Tailwind를 쓰려면 두가지 조건을 충족해야 한다라고 하는데 그 조건이 무엇인지 같이 알아보면 좋을 것 같다.

 

1. 프로젝트에 디자인 시스템이 있어야 한다.

Tailwind의 철학은 디자인 시스템과 함께할 때 빛이 나게 된다.

디자인 시스템이란, 디자이너와 개발자가 일관된 "디자인 토큰"을 사용하는 체계이다.

디자인 토큰은 색상, 간격, 글씨 크기 같은 값을 말한다.

 

만약 디자인 토큰 없이 개발하게 된다면

.button {
  background-color: oklch(45% 0.2 270);
}

.tab {
  background-color: oklch(45% 0.2 270);
}

.card-header {
  background-color: oklch(45% 0.2 270);
}

 

버튼, 탭, 카드 헤더가 같은 색이어야 한다고 가정해보자

이 상태에서 색상을 바꾸려면?
oklch(45% 0.2 270)을 전부 찾아서 일일이 수정해야 한다.
문제는 이 색이 무엇을 의미하는지 코드만 봐서는 알수가 없고 하나라도 빠트리면 UI 일관성이 깨지게 된다.

그래서 Tailwind에서는 tailwind.config.js에서 이런 디자인 토큰을 정의할수 있게 된다.

// tailwind.config.js
module.exports = {
  theme: {
    colors: {
      primary: 'oklch(45% 0.2 270)',
      secondary: 'oklch(60% 0.15 200)',
      error: 'oklch(54% 0.22 29)'
    },
    spacing: {
      sm: '4px',
      md: '8px',
      lg: '12px',
      xl: '16px'
    }
  }
}
<button class="bg-primary">Standard button</button>
<div class="bg-primary">First tab</div>
<header class="bg-primary">Card header</header>

<div class="p-4 mt-2 mb-6 gap-2">
  <span class="text-lg text-primary">다른 제목</span>
</div>

이렇게 값이 명확하고 일관성 있고 누가봐도 이해할 수 있게된다. 수정할 때도 config 파일 한곳만 수정하면 된다.

 

2. 컴포넌트 기반 접근 방식을 사용하고 있어야 한다

Tailwind는 유틸리티 클래스를 HTML에 직접 적용하는 방식이다. 그래서 클래스가 길어질 수밖에 없는데 컴포넌트화를 안 하면 어떻게 될까? 

아래 와 같이 버튼을 만들때마다 저 긴 코드를 복붙 해야 한다는 것이다 ..

이렇게 되면 DRY (Don't Repeat Yourself) 하지 않게 된다..!

<button class="flex items-center justify-center px-4 py-2 bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white font-medium rounded-lg shadow-md transition-colors duration-200">
  저장
</button>

<button class="flex items-center justify-center px-4 py-2 bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white font-medium rounded-lg shadow-md transition-colors duration-200">
  확인
</button>

<button class="flex items-center justify-center px-4 py-2 bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white font-medium rounded-lg shadow-md transition-colors duration-200">
  제출
</button>

 

 

하지만 이를 컴포넌트로 만들게 되면? 
긴 클래스는 컴포넌트 안에 캡슐화되고, 수정할 때도 한 곳만 고치면 전체에 반영된다.

// Button.tsx
const Button = ({ children }) => {
  return (
    <button className="flex items-center justify-center px-4 py-2 bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white font-medium rounded-lg shadow-md transition-colors duration-200">
      {children}
    </button>
  );
};


// 예시
<Button>저장</Button>
<Button>확인</Button>
<Button>제출</Button>

 

위와 같은 조건들로 Tailwind를 활용하면서도 주의해야 할 것이 있다.

컴포넌트화 하기 어려워 @apply를 사용하면 편할것 같다고 생각할 수 있다.

예를들어 아래 처럼 @apply로 클래스들을 추출해서 묶으면 사용할땐 깔끔하네? 할수도 있다.

/* @apply로 클래스 묶기 */
.btn-primary {
  @apply flex items-center justify-center px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white font-medium rounded-lg;
}

<button class="btn-primary">저장</button>

 

하지만 공식문서에선 @apply 사용을 자제하라고 한다.

@apply를 쓰는 순간, Tailwind의 핵심 가치가 사라지게 된다.

 

Tailwind의 장점이 클래스의 이름을 고민하지 않아도 된다 였는데

@apply를 사용하게 되면 .btn-primary 라는 이름을 다시 고민해야 한다..

 

HTML에서 스타일을 바로 확인하는게 장점이었는데! 다시 CSS 파일로 돌아가서 일일히 확인해야 한다.

또한 CSS 번들 사이즈도 증가하게 된다. 

결국 기존 CSS 작성 방식으로 돌아가는 것이다.

그래서 공식문서에서도 아래와 같이 이야기한다.

"단지 깔끔하게 보이려고 @apply를 사용하지 마세요.
Tailwind 클래스가 보기 안 좋은 건 맞습니다.
하지만 커스텀 CSS로 도배된 프로젝트를 유지보수하는 건 더 나쁩니다."

 


마무리

지금까지 Tailwind의  철학과 어떻게 쓰면 잘 사용할 수 있는지에 대해 공부를 해봤다.

핵심만 다시 짚어보면 이렇다.

- Tailwind의 핵심 철학은 "Utility-First"이다.

- 미리 정의된 클래스를 조합해서 스타일링하고, 클래스 이름 고민은 그만!

- 정해진 디자인 토큰을 사용해 UI 일관성은 자동으로 따라오게 되어있다.

- 잘 쓰려면 디자인 시스템과 컴포넌트 기반 접근 방식이 필요하다.

- @apply는 웬만하면 쓰지 말자..!

공부를 하면서 내가 정말 Tailwind를 아무 생각없이 사용했었다는 것을 알 수 있었다.

단지 Tailwind가 점유율이 높고 인기있는 CSS 프레임워크라서 사용하는 것이 아니라 왜 쓰는지 이해하고 사용한다면 훨씬 잘 활용할 수 있을 것 같다.

 

'공부 > Html & CSS' 카테고리의 다른 글

Headless UI 공부하면서 정리한 것들  (0) 2025.12.21
[HTML] <picture> 태그 알아보기  (0) 2025.10.22