개요

전통적으로 웹에서 무언가를 스타일링할 때는 CSS를 작성해야 합니다.

커스텀 디자인을 위해 커스텀 CSS를 작성하는 전통적인 방식

ChitChat

You have a new message!

<div class="chat-notification">
  <div class="chat-notification-logo-wrapper">
    <img class="chat-notification-logo" src="/img/logo.svg" alt="ChitChat Logo">
  </div>
  <div class="chat-notification-content">
    <h4 class="chat-notification-title">ChitChat</h4>
    <p class="chat-notification-message">You have a new message!</p>
  </div>
</div>

<style>
  .chat-notification {
    display: flex;
    align-items: center;
    max-width: 24rem;
    margin: 0 auto;
    padding: 1.5rem;
    border-radius: 0.5rem;
    background-color: #fff;
    box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
  }
  .chat-notification-logo-wrapper {
    flex-shrink: 0;
  }
  .chat-notification-logo {
    height: 3rem;
    width: 3rem;
  }
  .chat-notification-content {
    margin-left: 1.5rem;
  }
  .chat-notification-title {
    color: #1a202c;
    font-size: 1.25rem;
    line-height: 1.25;
  }
  .chat-notification-message {
    color: #718096;
    font-size: 1rem;
    line-height: 1.5;
  }
</style>

Tailwind를 사용하면 HTML에 미리 정의된 클래스를 직접 적용하여 엘리먼트를 스타일링할 수 있습니다.

CSS를 작성하지 않고 유틸리티 클래스를 사용해 커스텀 디자인을 구축

ChitChat

You have a new message!

<div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg flex items-center gap-x-4">
  <div class="shrink-0">
    <img class="size-12" src="/img/logo.svg" alt="ChitChat Logo">
  </div>
  <div>
    <div class="text-xl font-medium text-black">ChitChat</div>
    <p class="text-slate-500">You have a new message!</p>
  </div>
</div>

위 예제에서 우리는 다음과 같은 Tailwind 유틸리티를 사용했습니다:

  • 플렉스박스패딩 유틸리티 (flex, shrink-0, p-6)를 사용해 카드 레이아웃을 제어
  • 최대 너비마진 유틸리티 (max-w-sm, mx-auto)로 카드 너비를 제한하고 가로 중앙 정렬
  • 배경색, 둥근 모서리, 박스 그림자 유틸리티 (bg-white, rounded-xl, shadow-lg)로 카드 외관 스타일링
  • 크기 유틸리티 (size-12)로 로고 이미지의 너비와 높이 설정
  • 간격 유틸리티 (gap-x-4)로 로고와 텍스트 사이의 공간 조정
  • 글꼴 크기, 텍스트 색상, 글꼴 두께 유틸리티 (text-xl, text-black, font-medium 등)로 카드 텍스트 스타일링

이 방식으로 커스텀 CSS를 한 줄도 작성하지 않고 완전히 커스텀된 컴포넌트 디자인을 구현할 수 있습니다.

이제 여러분은 “이건 끔찍해, 정말 엉망진창이야!” 라고 생각할 수 있습니다. 맞습니다. 처음 보면 이게 좋은 아이디어라고 생각하기 어렵습니다. 직접 시도해봐야 합니다.

하지만 이 방식으로 무언가를 만들어보면 몇 가지 중요한 장점을 빠르게 깨닫게 됩니다:

  • 클래스 이름을 고민하지 않아도 됩니다. sidebar-inner-wrapper 같은 어색한 클래스 이름을 추가하거나, 단순히 플렉스 컨테이너인데 완벽한 추상적인 이름을 고민할 필요가 없습니다.
  • CSS가 더 이상 커지지 않습니다. 전통적인 방식에서는 새로운 기능을 추가할 때마다 CSS 파일이 커집니다. 유틸리티를 사용하면 모든 것이 재사용 가능하므로 새로운 CSS를 작성할 필요가 거의 없습니다.
  • 변경이 더 안전해집니다. CSS는 전역적이므로 변경할 때 무엇이 깨질지 알 수 없습니다. HTML의 클래스는 지역적이므로 다른 것이 깨질 걱정 없이 변경할 수 있습니다.

미리 정의된 유틸리티 클래스를 사용해 HTML만으로 작업할 때 얼마나 생산적일 수 있는지 깨닫게 되면, 다른 방식으로 작업하는 것이 고문처럼 느껴질 것입니다.


왜 인라인 스타일을 사용하지 않나요?

이 접근 방식에 대한 일반적인 반응은 “이건 그냥 인라인 스타일 아닌가요?”라는 의문입니다. 어떤 면에서는 맞습니다. 클래스 이름을 지정하고 그 클래스를 스타일링하는 대신 스타일을 직접 엘리먼트에 적용하고 있기 때문입니다.

하지만 유틸리티 클래스를 사용하면 인라인 스타일보다 몇 가지 중요한 장점이 있습니다:

  • 제약 조건을 통한 디자인. 인라인 스타일을 사용하면 모든 값이 마법의 숫자처럼 느껴집니다. 유틸리티를 사용하면 미리 정의된 디자인 시스템에서 스타일을 선택하므로 시각적으로 일관된 UI를 더 쉽게 구축할 수 있습니다.
  • 반응형 디자인. 인라인 스타일에서는 미디어 쿼리를 사용할 수 없지만, Tailwind의 반응형 유틸리티를 사용하면 완전한 반응형 인터페이스를 쉽게 구축할 수 있습니다.
  • 호버, 포커스 및 기타 상태. 인라인 스타일은 호버나 포커스와 같은 상태를 대상으로 할 수 없지만, Tailwind의 상태 변형을 사용하면 유틸리티 클래스로 이러한 상태를 쉽게 스타일링할 수 있습니다.

이 컴포넌트는 완전히 반응형이며 호버 및 포커스 스타일이 적용된 버튼을 포함하고 있으며, 전적으로 유틸리티 클래스로 구성되어 있습니다:

Woman's Face

Erin Lindford

Product Engineer

<div class="py-8 px-8 max-w-sm mx-auto space-y-2 bg-white rounded-xl shadow-lg sm:py-4 sm:flex sm:items-center sm:space-y-0 sm:gap-x-6">
  <img class="block mx-auto h-24 rounded-full sm:mx-0 sm:shrink-0" src="/img/erin-lindford.jpg" alt="Woman's Face" />
  <div class="text-center space-y-2 sm:text-left">
    <div class="space-y-0.5">
      <p class="text-lg text-black font-semibold">
        Erin Lindford
      </p>
      <p class="text-slate-500 font-medium">
        Product Engineer
      </p>
    </div>
    <button class="px-4 py-1 text-sm text-purple-600 font-semibold rounded-full border border-purple-200 hover:text-white hover:bg-purple-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-offset-2">Message</button>
  </div>
</div>

유지보수 고려사항

유틸리티 우선 접근 방식을 사용할 때 가장 큰 유지보수 문제는 자주 반복되는 유틸리티 조합을 관리하는 것입니다.

이 문제는 컴포넌트와 부분 추출에디터 및 언어 기능을 활용해 쉽게 해결할 수 있습니다. 멀티 커서 편집이나 간단한 반복문 같은 기능을 사용하면 됩니다.

<!-- PrimaryButton.vue -->
<template>
  <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
    <slot/>
  </button>
</template>

이 외에도, 유틸리티 우선 CSS 프로젝트를 유지보수하는 것은 대규모 CSS 코드베이스를 관리하는 것보다 훨씬 쉽습니다. HTML이 CSS보다 훨씬 관리하기 쉬운 구조이기 때문입니다. GitHub, Netflix, Heroku, Kickstarter, Twitch, Segment 등 대기업들이 이 방식을 성공적으로 사용하고 있습니다.

이 접근 방식에 대한 다른 사람들의 경험을 들어보고 싶다면 아래 자료를 참고하세요:

더 많은 정보를 원한다면 John Polacek이 정리한 The Case for Atomic/Utility-First CSS를 확인해 보세요.