최근 Next를 사용하면서 Tailwind CSS에 흥미가 생겨서 친해져보기로 했다. 예전에는 부트스트랩 느낌이라 별로 안좋아했는데, Emotion을 사용하면서 해결하지 못한 에러도 있었고 Styled Component에 애정이 조금 식어서 친해져보고 좋으면 이참에 갈아탈까 고민 중이다.
클래스를 많이 사용해서 HTML부분이 조금 지저분해지는 느낌은 있지만, 파일을 따로 분리하지 않아도되고 생산성이 높고 복잡한 CSS를 간단하게 만들어주는 클래스가 많아서 강력하기 때문에 단점보다는 장점이 더 많은 것 같다.
Next 프로젝트를 생성할 때 tailwind를 포함해서 생성하면 tailwind.config.ts
파일이 생성된 것을 볼 수 있는데 먼저 이 파일을 살펴보자.
// tailwind.config.ts
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
},
},
plugins: [],
};
export default config;
처음보면 조금 복잡해 보이지만 무슨 역할인지 알면 이해하기 쉽다.
tailwind는 빌드 타임에 CSS 파일을 사전에 생성하는 것이 아닌 사용되는 클래스에 따라 필요한 스타일만 동적으로 생성한다. 즉, tailwind에서 사용할 수 있는 모든 클래스를 먼저 가지고 있는 것이 아니라 우리가 작성한, 필요한 클래스 이름만 간추려서 CSS를 생성한다.
위의 tailwind.config.ts
는 tailwind의 설정 파일이다. 빌드 타임에 tailwind가 변환할 클래스 이름을 찾아내야 하는데, 이 설정파일에서 해당 클래스 이름이 위치한 파일의 경로를 알려주거나 테마, 플러그인 등을 설정해줄 수 있다.
파일의 내용을 하나하나 살펴보자.
content: 이 속성은 tailwind 클래스 이름을 탐색할 파일경로를 정의한다. 주어진 경로의 파일은 tailwind 클래스가 사용된 위치를 기준으로 스타일이 동적으로 생성된다.
theme: tailwind의 테마를 정의한다. 여기서 extend
를 사용해 기본 테마를 상속받아 확장할 수 있다. 사용자 지정 테마를 설정하는데 유용하게 사용할 수 있다.
plugins: tailwind에 추가할 사용자 정의 플러그인을 여기에 추가할 수 있다. 이 플러그인은 tailwind의 기능을 확장하거나 새로운 기능을 추가하는데 사용된다.
이렇게 어떤 역할을 하는지 왜 필요한지 알게되면 더 쉽게 이해하고 사용할 수 있을 것이다.
JIT 컴파일 모드는 필요한 클래스만 동적으로 생성하여 CSS 파일의 크기를 최적화하고 빌드 시간을 줄여준다.
JIT 컴파일러는 프로젝트 파일을 스캔해서 tailwind 클래스를 사용한 위치를 찾는다. 그런 다음 컴파일러는 프로젝트에서 실제로 사용한 클래스만 포함하는 최적화된 CSS 파일을 생성한다.
tailwind v2에서는 설정 파일에서 JIT 컴파일 모드를 설정할 수 있었지만, v3부터는 기본 컴파일 모드가 JIT으로 대체되었기 때문에 별도의 설정없이 기본으로 적용되어 있다.
프로젝트 생성시 global.css
파일을보면 아래와 같은 코드가 작성되어 있다.
// global.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind
와 같이 앞에 "@"가 붙은 코드를 Directives(지시어)라고 부른다.
Directives는 tailwind에 특별한 기능을 제공하고 더 효율적으로 작업할 수 있게 도와주는 도구들로 at-rules를 의미한다.
@tailwind base
: tailwind와 플러그인의 base style을 CSS에 주입한다.
@tailwind components
: tailwind에 사전 정의된 스타일 요소들을 활용하여 UI Component를 스타일링하는데 사용된다.
@tailwind utilities
: tailwind 유틸리티 클래스들을 CSS로 변환한다. 여기서 유틸리티 클래스란 여백, 높이, 색상 등을 말하는 것이다.
@tailwind Directive들은 컴파일러에서 생성된 클래스 이름으로 대체된다.
@apply
는 CSS파일에서 tailwind 유틸리티 클래스를 감싸주는 디렉티브다. HTML 태그에 작성하던 유틸리티 클래스를 CSS파일에서도 사용할 수 있게 해준다.
아래와 같이 유틸리티 클래스를 하나로 묶어서 사용할 수 있다.
.btn {
@apply w-fill bg-black h-10;
}
이제 hml에 .btn을 넣어주면 안에 있는 유틸리티 클래스가 모두 적용된다.
@layer
는 각각의 디렉티브를 상속받아 확장할 수 있게 해주는 디렉티브다.
@layer base {
button {
@apply w-fill bg-black h-10;
}
}
위와 같이 레이어 디렉티브를 적용하면 모든 button 태그에 기본 스타일로 적용된다.
@layer utilities {
.my-button {
@apply w-fill bg-black h-10;
}
}
utilities를 확장하면 유틸리티 클래스를 만들어서 사용할 수 있다.
이제 처음 생성된 파일들에 대해서는 이해가 끝났으니 자주 사용하는 클래스들을 알아보자.
Modifier는 스타일을 조건부로 적용할 수 있도록 도와준다.
Modifier는 항상 끝에 :
(colon)을 가지고 있다. modifier는 특정 조건이고 : 뒤에 붙는 것이 특정 조건이 참일 때 적용될 CSS가 된다.
유틸리티를 사용해 마우스 호버, 포커스 등에 대한 요소의 상태에 따른 스타일을 지정해줄 수 있다.
<button class="bg-violet-500 hover:bg-violet-600 active:bg-violet-700 focus:outline-none focus:ring focus:ring-violet-300 ...">
Save changes
</button>
CSS 선택자처럼 사용할 수 있는 First, last, odd, and even도 있다.
<ul role="list" class="p-6 divide-y divide-slate-200">
{#each people as person}
<!-- Remove top/bottom padding when first/last child -->
<li class="flex py-4 first:pt-0 last:pb-0">
<img class="h-10 w-10 rounded-full" src="{person.imageUrl}" alt="" />
<div class="ml-3 overflow-hidden">
<p class="text-sm font-medium text-slate-900">{person.name}</p>
<p class="text-sm text-slate-500 truncate">{person.email}</p>
</div>
</li>
{/each}
</ul>
<table>
<!-- ... -->
<tbody>
{#each people as person}
<!-- Use a white background for odd rows, and slate-50 for even rows -->
<tr class="odd:bg-white even:bg-slate-50">
<td>{person.name}</td>
<td>{person.title}</td>
<td>{person.email}</td>
</tr>
{/each}
</tbody>
</table>
이 외에도 양식 상태를 확인하는 required:
, invalid:
등과 같은 Modifier가 있다.
반응형 디자인 또한 Modifier를 사용할 수 있다.
중단점 접두사 | 최소너비 | CSS |
---|---|---|
sm: | 640px | @media (min-width: 640px) { ... } |
md: | 768px | @media (min-width: 768px) { ... } |
lg: | 1024px | @media (min-width: 1024px) { ... } |
xl: | 1280px | @media (min-width: 1280px) { ... } |
2xl: | 1536px | @media (min-width: 1536px) { ... } |
tailwind 다크모드는 웹 브라우저의 설정을 감지해서 적용된다.
<div class="bg-white dark:bg-slate-800 rounded-lg px-6 py-8 ring-1 ring-slate-900/5 shadow-xl">
<div>
<span class="inline-flex items-center justify-center p-2 bg-indigo-500 rounded-md shadow-lg">
<svg class="h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"><!-- ... --></svg>
</span>
</div>
<h3 class="text-slate-900 dark:text-white mt-5 text-base font-medium tracking-tight">Writes Upside-Down</h3>
<p class="text-slate-500 dark:text-slate-400 mt-2 text-sm">
The Zero Gravity Pen can be used to write in any orientation, including upside-down. It even works in outer space.
</p>
</div>
공식문서에서 수동으로 다크 모드를 전환할 수도 있다.
공식 문서
Dark Mode
더 구체적인 상황을 대상으로 하기 위해 Modifier를 중첩할 수 있다.
<button class="dark:md:hover:bg-fuchsia-600 ...">
Save changes
</button>
상위 요소의 상태에 따라 요소의 스타일을 지정할 수도 있는데, 상위 요소를 group
클래스로 표시하고 대상 요소의 스타일을 지정하는 group-*
수정자를 사용한다.
<a href="#" class="group block max-w-xs mx-auto rounded-lg p-6 bg-white ring-1 ring-slate-900/5 shadow-lg space-y-3 hover:bg-sky-500 hover:ring-sky-500">
<div class="flex items-center space-x-3">
<svg class="h-6 w-6 stroke-sky-500 group-hover:stroke-white" fill="none" viewBox="0 0 24 24"><!-- ... --></svg>
<h3 class="text-slate-900 group-hover:text-white text-sm font-semibold">New project</h3>
</div>
<p class="text-slate-500 group-hover:text-white text-sm">Create a new project from a variety of starting templates.</p>
</a>
형제 요소의 상태에 따라 요소의 스타일을 지정해야 하는 경우 형제를 peer
클래스로 표시하고 대상 요소의 스타일을 지정하는 peer-*
수정자를 사용한다.
<form>
<label class="block">
<span class="block text-sm font-medium text-slate-700">Email</span>
<input type="email" class="peer ..."/>
<p class="mt-2 invisible peer-invalid:visible text-pink-600 text-sm">
Please provide a valid email address.
</p>
</label>
</form>
tailwind의 모든 것을 정리하지는 않았고 기존에 사용하면서 햇갈리고 어려웠던 부분들만 간추려서 간단하게 정리했다.
아마 다른 기본적인 것들은 공식문서에서 찾는 것이 더 쉽고 빠를 것이다.
앞으로 진행할 사이드 프로젝트에서 tailwind를 사용할 것이다. 지금까지는 딱히 오류가 발생하거나 그럴만한 요소는 보이지 않기 때문에 프로젝트를 진행하면서 CSS로 머리아플 일은 없을 것 같다.