Hello Tailwind CSS! | 장점, 단점, 사용법
일관된 디자인을 유지하면서도 쉽고 빠르게 스타일링하기
이번 블로그에 도입한 Tailwind CSS를 소개하고자 한다. 마음에 쏙 드는 CSS 프레임워크로 인라인 스타일을 사용하는 것만큼 쉽고 빠르게 스타일링을 할 수 있으면서도 디자인 시스템만큼이나 일관된 디자인을 가능하게 해준다. GitHub과 Nuxt.js 공식 사이트에서 사용하고 있기도 하다. styled-components 등과 같이 작은 스타일 변경에도 컴포넌트를 만들어야 하는 번거로움에 지쳤거나 매번 클래스명을 고민하느라 골머리를 썩였던 분들이 참고하면 좋다.
시작하기
이번에 Gatsby와 React를 사용하여 블로그를 개발하면서 스타일링 방식에 대해 고민하게 되었다. 회사에서는 주로 Vue를 사용하고 있고, Vue는 기본적으로 컴포넌트로 스코프가 제한된 스타일 템플릿을 제공하기에 스타일링 방식에 대해 크게 고민할 필요가 없었다.
이전에 React를 사용했을 때는 Vue처럼 컴포넌트로 스코프가 제한된 스타일 템플릿을 제공하면서도 styled-components처럼 CSS 코드에서 JS 코드를 활용할 수 있는 styled-jsx를 사용했었다.
Vue의 스타일 템플릿이나 styled-jsx 모두 HTML 코드와 CSS 코드를 오가는 게 번거로웠고, 수정할 때마다 클래스명을 검색해서 찾는 과정이 그리 편하게 느껴지지 않았었다.
블로그 개발을 시작할 때는 새로운 기술을 써볼 겸 styled-components를 사용했는데 작은 마진 하나 추가할 때도 새로운 컴포넌트를 만들어야 해서 여간 성가신 게 아니었다. 또 에디터에서 포맷팅을 제공한다 한들 취향상 코드를 문자열 안에 작성하는 것은 마음에 들지 않았다.
이런 이유로 새로운 스타일링 방식을 찾다가 Tailwind CSS를 발견했다. 나와 비슷한 불편함을 느낀 사람들이라면 한 번쯤 참고해보면 좋을 CSS 프레임워크로 더 많은 개발자들이 Tailwind CSS의 편리함을 알았으면 좋겠기에 이번 글에서 약을 팔고자소개하고자 한다.
Tailwind CSS란 무엇인가?
Tailwind CSS는 Utility-First 컨셉을 가진 CSS 프레임워크다. 부트스트랩과 비슷하게 m-1
, flex
와 같이 미리 세팅된 유틸리티 클래스를 활용하는 방식으로 HTML 코드 내에서 스타일링을 할 수 있다.
<button class="py-2 px-4 rounded-lg shadow-md text-white bg-blue-500">
Click me
</button>
Tailwind CSS의 장점
Utility-First의 편리함과 빠른 개발
Utility-First 컨셉은 Tailwind CSS의 메인 컨셉이자 가장 큰 장점이다. 이 글에서도 볼 수 있듯 Utility-First 덕에 매우 쉽고 빠르게 원하는 디자인을 개발할 수 있게 된다.
스타일 코드도 HTML 코드 안에 있기 때문에 HTML와 CSS 파일을 별도로 관리할 필요가 없다. 그 덕분에 HTML-CSS를 왔다갔다하며 시간을 쓰거나 위의 이미지처럼 화면을 분할해서 사용하지 않아도 된다. 또 원하는 태그의 스타일을 변경하기 위해 클래스명을 검색해가며 일일이 필요한 CSS 코드를 찾을 수고도 사라진다.
또 마크업을 하다 보면 반드시 겪게 되는 고퉁 중에 하나는 랩핑하는 태그의 클래스명을 고민하는 일이다. BEM, OOCSS 등의 방법론이 나올 정도로 클래스명 짓는 일은 까다롭다. 어렵사리 규칙을 잘 정해도 그리 효율적이지도 않은 경우가 많다. Tailwind CSS를 사용하면 랩핑 태그의 클래스명을 사용할 일이 거의 없으므로 container
, wrapper
, inner-wrapper
와 같은 클래스명을 고민하지 않아도 된다.
실제로 이번에 블로그를 개발할 때 styled-components를 사용했을 때보다 Tailwind CSS를 사용했을 때 2배 이상 빨랐다. Tailwind CSS를 사용하여 블로그 하나를 하루 만에 모두 개발할 수 있었다.
일관된 디자인
모든 곳에서 동일한 색상이나 사이즈, 간격 등의 유틸리티 클래스를 사용하므로 일관된 스타일로 구현하기가 수월하다.
쉽고 자유로운 커스텀
Tailwind CSS는 다른 프레임워크들에 비해 기본 스타일 값을 디테일한 부분까지 쉽게 커스텀이 가능하다. 커스텀을 할 때 기본 스타일 값을 수정하는 방식이기에 디자인 일관성도 해치지 않는다. 덕분에 디자인 시스템이나 다크 모드 구현도 간편하다.
로우 레벨의 스타일 제공
각 CSS 요소 수준의 유틸리티 클래스를 제공하기 때문에 세밀하게 원하는 디자인을 구현할 수 있다.
Intelli Sense
로우 레벨의 스타일을 제공한다는 것은 거의 모든 스타일의 유틸리티 클래스를 학습해야 한다는 의미와 같다. 이러한 불편을 해소하기 위해 Intelli Sense 플러그인을 제공한다. 미리보기, 자동완성, 신택스 하이라이팅, 린팅을 지원하기 때문에 조금만 익숙해지면 금방 문서 없이 개발할 수 있다.
JavaScript 코드와의 분리
Tailwind CSS는 JavaScript 코드와 완전히 분리되어 있다. 그러므로 프로젝트 진행 도중 JavaScript 프레임워크를 변경하여도 큰 추가 작업 없이 기존의 HTML 코드를 그대로 쓸 수 있다.
Tailwind CSS의 단점
못생긴 코드
<div
class="bg-primary-darken text-bold text-white inline-flex items-center p-4 rounded shadow-md"
>
Not Pretty Code 😵
</div>
아무래도 가장 큰 단점은 코드가 못생겼다는 점이다. 아마 Tailwind CSS에서 가장 큰 진입장벽이 아닐까 싶다 😂 직관적이라고 할 수도 있겠지만 예쁘다고 말하기는 어렵다.
초반 클래스명 러닝 커브
초반에는 각 스타일의 클래스명을 익히느라 개발하는 내내 문서를 참고해야 하는 번거로움이 있다. 그래도 대부분의 클래스명이 기존 CSS 속성이나 속성값과 비슷한 경우가 많고 자동완성을 지원하는 Intelli Sense 플러그인이 있어서 금방 익숙해지기는 한다.
JavaScript 코드 사용 불가
클래스명을 분기 처리하여 동적으로 스타일링을 설정할 수는 있지만 styled-components와 같이 JavaScript 변수 값에 따라 가로 길이를 설정하는 등의 구현은 가능하기는 하지만 무척 번거로운 설정이 필요하다. 그러나 나는 이렇게 특정 변수값을 활용하여 스타일링을 하는 경우가 일관된 디자인을 해치는 경우가 많기에 지양하는 편이다. 실제로 블로그를 구현할 때 이러한 설정이 필요한 경우가 한 번도 없었다.
HTML와 CSS 코드 혼재
Tailwind CSS의 단점을 꼽을 때 HTML와 CSS의 관심사 분리가 이루어지지 않았다고 언급되는 경우가 있다. 그래서 단점의 한 꼭지로 넣었긴 했으나 개인적으로 HTML와 CSS를 다른 관심사로 분리할 수 있는가에 대한 의문이 남아있기는 하다.
Tailwind CSS 사용하기
설치하기
사용하는 프레임워크나 도구에 따라 설치 방법이 조금씩 다르다. 공식 문서에는 Next.js, Vue3, Laravel, Nuxt.js, Create React App, Gatsby 설치 방법이 나와있다.
기본적으로 PostCSS 플러그인으로 설치할 것을 권장한다. PostCSS를 사용할 수 없는 환경인 경우에 다른 방법으로 설치할 수는 있으나 PostCSS를 사용하면 auto prefix와 같이 편리한 기능을 사용할 수 있기 때문에 나 또한 PostCSS를 사용하기를 추천한다. 그러므로 이 글에서는 PostCSS 플러그인으로 설치하는 방법을 소개한다.
npm으로 Tailwind CSS 설치하기
Tailwind CSS v2 부터는 IE를 지원하지 않기 때문에 PostCSS의 autoprefixer 등을 함께 사용해야 한다.
npm install tailwindcss@latest postcss@latest autoprefixer@latest
PostCSS 플러그인에 Tailwind CSS 추가하기
// postcss.config.js 등의 postcss 설정 파일
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
설정 파일 생성하기
npx tailwindcss init
위의 명령어를 입력하면 프로젝트 루트에 아래의 설정 파일이 생성된다. 기본 스타일이나 플러그인 등을 설정할 수 있는 파일이다.
// tailwind.config.js
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {},
plugins: [],
};
Tailwind CSS 스타일 추가하기
메인 CSS 파일에 아래 코드를 추가하여 Tailwind CSS 스타일을 추가한다. @tailwind
디렉티브는 빌드 시에 CSS 코드로 변환된다.
@tailwind base;
@tailwind components;
@tailwind utilities;
만일 React나 Vue와 같이 CSS 파일을 JavaScript에 직접 임포트할 수 있는 경우에는 아래와 같이 JavaScript 코드에서 직접 임포트할 수도 있다.
// app.js
import "tailwindcss/tailwind.css";
최적화하기
파일 크기를 최소화하기 위해 purge
옵션을 사용한다. 프로덕션으로 빌드할 때 여기에 설정된 파일에서 사용되지 않는 모든 클래스는 제거된다.
// tailwind.config.js
module.exports = {
purge: ['./src/**/*.{js,jsx,ts,tsx}'],
...
}
기본 설정 커스텀하기
위에서 말했듯 Tailwind CSS는 기본 스타일 값을 쉽게 커스텀할 수 있다. 아래와 같이 색상이나 특정 스타일, 변수 등 웬만한 것을 커스텀할 수 있고, 원한다면 JavaScript 코드를 활용할 수도 있다.
// tailwind.config.js
module.exports = {
theme: {
colors: {
gray: colors.coolGray,
blue: colors.lightBlue,
red: colors.rose,
pink: colors.fuchsia,
},
fontFamily: {
sans: ["Graphik", "sans-serif"],
serif: ["Merriweather", "serif"],
},
},
};
더 자세한 내용은 여기에서 확인할 수 있다.
기본 스타일을 설정할 때 주의할 점은 실수로 기본 스타일 값을 오버라이딩 하지 않는 것이다. extend
객체 안에 넣어주지 않으면 기본 스타일 값이 덮어써지므로 아래와 같이 extend
를 잘 활용하도록 한다.
module.exports = {
...
theme: {
...
extend: {
colors: {
primary: '#8ffebf',
},
...
},
},
variants: {
extend: {
borderWidth: ['hover'],
},
},
...
}
사용하기
<button
class="py-2 px-4 font-semibold rounded-lg shadow-md text-white bg-green-500 hover:bg-green-700"
>
Hello, Tailwind CSS!
</button>
위의 코드와 같이 클래스명을 입력하는 것만으로 스타일링을 할 수 있다. 위에서 사용한 각 클래스는 아래와 같은 스타일을 가지게 된다.
class | properties |
---|---|
py-2 | padding-top: 0.5rem; padding-bottom: 0.5rem; |
font-semibold | font-weight: 600; |
rounded-lg | border-radius: 0.5rem; |
shadow-sm | --tw-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); |
... | ... |
이 외의 모든 유틸리티 클래스는 여기에서 찾을 수 있다.
반복되는 스타일 설정하기
만일 버튼이나 사이드바 메뉴와 동일한 스타일을 여러 번 사용하게 되는 경우 아래처럼 유틸리티 클래스를 추가로 만들어서 사용할 수도 있다.
<button class="btn btn-green mr-4">Button</button>
<button class="btn btn-blue">Button</button>
<style>
.btn {
@apply py-2 px-4 font-semibold rounded-lg shadow-md;
}
.btn-green {
@apply text-white bg-green-500 hover:bg-green-700;
}
.btn-blue {
@apply text-white bg-blue-500 hover:bg-blue-700;
}
</style>
hover 등의 상태 스타일 설정하기
hover:xx
와 같은 형태로 상태 스타일을 손쉽게 설정할 수 있다.
<button class="bg-red-500 hover:bg-red-700 ...">Hover me</button>
자식 태그들을 그룹핑하여 부모 태그의 상태값에 따라 반영되도록 설정할 수도 있다.
New Project
Create a new project from a variety of starting templates.
<div
className="group border-indigo-500 hover:bg-white hover:shadow-lg hover:border-transparent ..."
>
<p className="text-indigo-600 group-hover:text-gray-900 ...">New Project</p>
<p className="text-indigo-500 group-hover:text-gray-500 ...">
Create a new project from a variety of starting templates.
</p>
</div>
반응형 스타일 설정하기
반응형에 대한 스타일도 쉽게 설정이 가능하다. 모바일 퍼스트이며 md:XX
와 같이 prefix에 설정한 breakpoint 값에 따라 변경된다.
<div class="bg-yellow-500 lg:bg-yellow-700 ...">Resize Window</div>
자식 태그 간격 설정하기
리스트 등을 구현할 때 각 아이템 사이의 간격을 쉽게 설정할 수 있다.
<div class="flex space-x-4">
<div v-for="item in items" :key="item" class="...">{{ item }}</div>
</div>
자식 태그 순서에 따른 스타일 설정
메뉴 등을 스타일링할 때 마지막 메뉴만 오른쪽 마진을 주지 않는 등의 자식 요소 설정도 쉽다. 자식 태그 클래스에 hover:
와 같이 last:
프리픽스를 사용한다.
<div class="...">
<div v-for="item in items" :key="item" class="transform last:rotate-45 ...">
{{ item }}
</div>
</div>
단, last:
프리픽스는 기본으로 설정되어 있지 않기 때문에 아래와 같은 설정이 필요하다.
// tailwind.config.js
module.exports = {
// ...
variants: {
extend: {
rotate: ["last"],
},
},
};
마치며
이번에 Tailwind CSS를 사용하여 블로그를 개발하면서 마크업 개발에 대한 만족도가 매우 높아졌다. 당분간은 웬만한 마크업 시에는 Tailwind CSS를 사용할 것 같다. 특히 디자인 시스템을 구현해야 하는 경우에는 더더욱 Tailwind CSS를 사용할 것 같다. 클래스명을 설정하는 것만으로도 디자인 시스템의 색상이나 간격, 사이즈 등을 빠르게 반영할 수 있기 때문이다.
Utility-First 방식은 올드하다고만 생각했는데 이번에 Tailwind CSS를 사용해보면서 어떻게 구현했는지에 따라 충분히 세련될 수 있음을 새삼 깨달았다. 더 많은 분들이 이 편한 Tailwind CSS를 써보면 좋겠다! 🙏
Reference
- Tailwind CSS official site
- Utility-first CSS: Ridiculously fast front-end development for almost every design - Sascha Wolff
- Utility-first CSS - You have to try it first! - Michael Z
- Tailwindcss를 소개합니다.(with. twin.macro + emotion) - SOSOLOG