핵심 개념
제한된 기본 유틸리티 세트를 사용해 복잡한 컴포넌트를 구축하는 방법.
전통적으로 웹에서 무언가를 스타일링할 때는 CSS를 작성해야 합니다.
커스텀 디자인을 위해 커스텀 CSS를 작성하는 전통적인 방식
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를 작성하지 않고 유틸리티 클래스를 사용해 커스텀 디자인을 구축
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
같은 어색한 클래스 이름을 추가하거나, 단순히 플렉스 컨테이너인데 완벽한 추상적인 이름을 고민할 필요가 없습니다.미리 정의된 유틸리티 클래스를 사용해 HTML만으로 작업할 때 얼마나 생산적일 수 있는지 깨닫게 되면, 다른 방식으로 작업하는 것이 고문처럼 느껴질 것입니다.
이 접근 방식에 대한 일반적인 반응은 “이건 그냥 인라인 스타일 아닌가요?”라는 의문입니다. 어떤 면에서는 맞습니다. 클래스 이름을 지정하고 그 클래스를 스타일링하는 대신 스타일을 직접 엘리먼트에 적용하고 있기 때문입니다.
하지만 유틸리티 클래스를 사용하면 인라인 스타일보다 몇 가지 중요한 장점이 있습니다:
이 컴포넌트는 완전히 반응형이며 호버 및 포커스 스타일이 적용된 버튼을 포함하고 있으며, 전적으로 유틸리티 클래스로 구성되어 있습니다:
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를 확인해 보세요.