# 챕터 8: Tailwind CSS 실전 활용법
## 서론
지난 챕터에서 Tailwind CSS의 기본 개념과 주요 유틸리티 클래스들을 배웠습니다. 이제는 실제 프로젝트에서 활용할 수 있는 고급 기능들을 알아볼 차례입니다. 현대 웹은 다양한 기기에서 완벽하게 작동해야 하며, 복잡한 레이아웃을 효율적으로 구성할 수 있어야 합니다.
이번 챕터에서는 Tailwind CSS의 반응형 디자인 시스템, Flexbox와 Grid를 활용한 레이아웃 구성, 그리고 커스텀 설정을 통한 확장 방법을 배워보겠습니다. 이 내용들을 마스터하면 여러분은 어떤 디자인 요구사항도 Tailwind CSS로 구현할 수 있게 될 것입니다.
## 본론
### 반응형 디자인의 핵심 원리
Tailwind CSS는 모바일 우선(Mobile-First) 접근 방식을 채택합니다. 기본 스타일은 모바일을 위한 것이고, 더 큰 화면을 위한 스타일은 반응형 접두사를 사용합니다. Tailwind의 기본 브레이크포인트는 다음과 같습니다:
- sm: 640px 이상
- md: 768px 이상
- lg: 1024px 이상
- xl: 1280px 이상
- 2xl: 1536px 이상
export default function ResponsiveDesign() {
return (
<div className="p-4 md:p-8 lg:p-12">
<h1 className="text-xl md:text-2xl lg:text-3xl xl:text-4xl font-bold mb-4">
화면 크기에 따라 변하는 제목
</h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
<div className="bg-blue-500 text-white p-4 rounded">
<h3 className="font-bold mb-2">반응형 카드 1</h3>
<p className="text-sm md:text-base">
모바일에서는 한 열로, 태블릿에서는 두 열로,
데스크톱에서는 세 열로 표시됩니다.
</p>
</div>
<div className="bg-green-500 text-white p-4 rounded">
<h3 className="font-bold mb-2">반응형 카드 2</h3>
<p className="text-sm md:text-base">
Tailwind의 반응형 시스템은 매우 직관적입니다.
</p>
</div>
<div className="bg-purple-500 text-white p-4 rounded">
<h3 className="font-bold mb-2">반응형 카드 3</h3>
<p className="text-sm md:text-base">
각 브레이크포인트에서 다른 스타일을 적용할 수 있습니다.
</p>
</div>
<div className="bg-red-500 text-white p-4 rounded">
<h3 className="font-bold mb-2">반응형 카드 4</h3>
<p className="text-sm md:text-base">
큰 화면에서만 네 번째 카드가 한 줄에 표시됩니다.
</p>
</div>
</div>
{/* 반응형 숨김/표시 */}
<div className="mt-8">
<p className="block md:hidden bg-yellow-100 p-4 rounded">
📱 모바일에서만 보이는 메시지입니다
</p>
<p className="hidden md:block lg:hidden bg-blue-100 p-4 rounded">
💻 태블릿에서만 보이는 메시지입니다
</p>
<p className="hidden lg:block bg-green-100 p-4 rounded">
🖥️ 데스크톱에서만 보이는 메시지입니다
</p>
</div>
</div>
)
}
### CSS Position 이해하기 - 레이아웃의 기초
여기서 이해해야 할 중요한 개념이 있습니다. 바로 Position입니다. Position은 요소가 페이지에서 어떻게 배치되는지를 결정하는 CSS의 핵심 속성입니다.
Position의 5가지 종류:
static (기본값): 일반적인 문서 흐름
relative: 원래 위치 기준으로 이동 + absolute의 기준점 역할
absolute: 가장 가까운 positioned 부모 기준으로 절대 위치
fixed: 브라우저 창 기준으로 고정
sticky: 스크롤에 따라 relative ↔ fixed 전환
Position 속성들의 관계
핵심 개념: "기준점"의 관계
가장 중요한 규칙 하나만 기억하세요:
Absolute는 static이 아닌 가장 가까운 부모를 기준으로 합니다
1. Static(기본값) ↔ Relative(기준점) 관계
// ❌ 기준점이 없는 경우
<div> {/* static */}
<div> {/* static */}
<div className="absolute top-0 right-0">절대위치</div> {/* 페이지 전체 기준! */}
</div>
</div>
// ✅ 기준점이 있는 경우
<div className="relative"> {/* 기준점 역할! */}
<div> {/* static */}
<div className="absolute top-0 right-0">절대위치</div> {/* relative 부모 기준 */}
</div>
</div>
핵심: Static은 기준점이 될 수 없고, Relative는 기준점이 됩니다.
2. Relative의 이중 역할
<div className="relative top-4"> {/* 1️⃣ 자신도 위치 이동 */}
<span>일반 내용</span>
<div className="absolute top-0 right-0"> {/* 2️⃣ 자식의 기준점도 됨 */}
배지
</div>
</div>
핵심: Relative는 자기 자신도 움직이고 + 자식들의 기준점도 됩니다.
3. Absolute ↔ Fixed 차이점
// Absolute: 부모를 찾아서 기준 삼음
<div className="relative"> {/* 이것이 기준점 */}
<div className="absolute top-0">배지</div>
</div>
// Fixed: 항상 화면이 기준 (부모 무시)
<div className="relative"> {/* 무시됨 */}
<div className="fixed top-0">네비바</div> {/* 화면 기준 */}
</div>
핵심: Absolute는 부모에 의존적, Fixed는 독립적입니다.
4. Sticky의 변신
<div className="sticky top-0"> {/* 평소엔 relative처럼 */}
헤더 {/* 스크롤하면 fixed처럼 */}
</div>
<div>내용1</div>
<div>내용2</div> {/* 스크롤해보세요! */}
핵심: 상황에 따라 relative ↔ fixed 사이를 자동 전환합니다.
관계 요약표
| Position | 역할 | 기준점 될 수 있나? | 언제사용? |
| static | 기본값 | ❌ 안됨 | 일반 내용 |
| relative | 이동 + 기준점 | ✅ 됨 | 컨테이너 역할 |
| absolute | 기준점 찾아서 배치 | ✅ 됨 | 정확한 위치 |
| fixed | 화면 고정 | ✅ 됨 | 네비바, 버튼 |
| sticky | 조건부 고정 | ✅ 됨 | 스마트 헤더 |
실전 예시: 미니 웹사이트로 모든 Position 이해하기
export default function PositionDemo() {
return (
<div className="max-w-4xl mx-auto">
{/* Fixed 네비게이션 - 스크롤해도 고정됨 */}
<nav className="fixed top-0 left-0 right-0 bg-blue-600 text-white p-4 z-50">
<div className="max-w-4xl mx-auto flex justify-between items-center">
<h1 className="text-xl font-bold">MyWebsite</h1>
<div className="relative">
{/* Relative 부모 안에 Absolute 알림 배지 */}
<button className="bg-blue-500 px-4 py-2 rounded">알림</button>
<span className="absolute -top-2 -right-2 bg-red-500 text-xs w-5 h-5 rounded-full flex items-center justify-center z-10">
3
</span>
</div>
</div>
</nav>
{/* Static 콘텐츠 - 일반적인 문서 흐름 */}
<main className="pt-20"> {/* Fixed 네비 때문에 padding-top 추가 */}
{/* Sticky 헤더 - 스크롤 시 상단에 고정 */}
<div className="sticky top-16 bg-gray-100 p-4 z-40 border-b">
<h2 className="text-lg font-semibold">스티키 섹션 헤더</h2>
</div>
{/* 일반 콘텐츠 영역 */}
<div className="p-8 space-y-6">
<div className="bg-white p-6 rounded shadow">
<h3 className="text-lg font-bold mb-2">Static 요소들</h3>
<p className="text-gray-600 mb-4">
이 문단들은 모두 static positioning입니다.
일반적인 문서 흐름에 따라 위에서 아래로 배치됩니다.
</p>
{/* Relative 요소 - 원래 위치에서 살짝 이동 */}
<div className="relative left-4 bg-yellow-100 p-3 rounded inline-block">
Relative: 원래 위치에서 오른쪽으로 1rem 이동
</div>
</div>
{/* Absolute를 위한 Relative 컨테이너 */}
<div className="relative bg-gray-50 p-8 rounded h-64">
<h3 className="text-lg font-bold">Relative 컨테이너</h3>
<p className="text-gray-600 mt-2">
이 영역은 relative 포지셔닝되어
내부 absolute 요소들의 기준점이 됩니다.
</p>
{/* Absolute 요소들 */}
<div className="absolute top-4 right-4 bg-green-500 text-white p-3 rounded z-20">
Absolute: 우상단
</div>
<div className="absolute bottom-4 left-4 bg-purple-500 text-white p-3 rounded z-10">
Absolute: 좌하단
</div>
{/* Z-index 예시 - 겹치는 요소들 */}
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<div className="absolute w-16 h-16 bg-red-500 opacity-75 z-10"></div>
<div className="absolute w-16 h-16 bg-blue-500 opacity-75 z-20 top-2 left-2"></div>
<div className="absolute w-16 h-16 bg-green-500 opacity-75 z-30 top-4 left-4"></div>
</div>
</div>
{/* 스크롤을 위한 더 많은 콘텐츠 */}
<div className="space-y-4">
{[1,2,3,4,5].map(num => (
<div key={num} className="bg-white p-6 rounded shadow">
<h4 className="font-semibold">콘텐츠 섹션 {num}</h4>
<p className="text-gray-600 mt-2">
스크롤해보세요! Fixed 네비게이션은 계속 위에 고정되고,
Sticky 헤더는 네비게이션 아래에 고정됩니다.
</p>
</div>
))}
</div>
</div>
</main>
{/* Fixed 플로팅 버튼 */}
<button className="fixed bottom-6 right-6 bg-blue-500 text-white w-14 h-14 rounded-full shadow-lg hover:bg-blue-600 transition-colors z-50 flex items-center justify-center">
💬
</button>
</div>
)
}
Position 예시 위치특징
| fixed | 상단 네비 + 플로팅 버튼 | 스크롤해도 항상 같은 자리 |
| sticky | 섹션 헤더 | 처음엔 일반 배치, 스크롤 시 고정 |
| relative | 컨테이너 + 노란 박스 | absolute의 기준점 + 약간의 위치 이동 |
| absolute | 알림 배지 + 모서리 박스들 | 부모(relative) 안에서 정확한 위치 |
| static | 모든 일반 텍스트와 카드 | 기본값, 일반적인 문서 흐름 |
Z-index 값들:
- z-50: Fixed 요소들 (네비, 버튼) - 가장 위
- z-40: Sticky 헤더
- z-30, z-20, z-10: 겹치는 요소들의 순서
### Flexbox 레이아웃 마스터하기
Flexbox는 일차원 레이아웃을 만드는 강력한 도구입니다. Tailwind CSS는 Flexbox의 모든 기능을 간단한 클래스로 제공합니다:
Flexbox는 일차원 레이아웃을 만드는 강력한 도구입니다. "일차원"이라는 것은 한 번에 한 방향(가로 또는 세로)으로만 요소를 배치한다는 뜻입니다. Flexbox를 사용하면 요소들을 쉽게 정렬하고, 남은 공간을 분배하며, 크기를 조절할 수 있습니다.
Flexbox를 언제 사용할까요?
내비게이션 바에서 메뉴 항목들을 수평으로 정렬할 때
버튼들을 한 줄에 나란히 배치할 때
카드 내부의 제목, 내용, 버튼을 세로로 배치할 때
요소를 정확히 중앙에 배치하고 싶을 때
Flexbox의 핵심 개념:
Flex Container: flex 클래스를 적용한 부모 요소
Flex Items: Flex Container 안에 있는 자식 요소들
Main Axis: 주축 (기본적으로 가로 방향)
Cross Axis: 교차축 (주축에 수직인 방향)
주요 Tailwind Flexbox 클래스들:
flex: 요소를 Flex Container로 만듭니다
justify-center: 주축 방향으로 중앙 정렬 (가로 중앙)
items-center: 교차축 방향으로 중앙 정렬 (세로 중앙)
flex-col: 세로 방향으로 배치
gap-4: 요소들 사이에 간격 추가
export default function FlexboxLayout() {
return (
<div className="p-8">
<h2 className="text-2xl font-bold mb-6">Flexbox 레이아웃 예제</h2>
{/* 기본 Flex 컨테이너 */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">기본 Flex 정렬</h3>
<div className="flex gap-4 bg-gray-100 p-4 rounded">
<div className="bg-blue-500 text-white p-4 rounded">아이템 1</div>
<div className="bg-blue-500 text-white p-4 rounded">아이템 2</div>
<div className="bg-blue-500 text-white p-4 rounded">아이템 3</div>
</div>
</div>
{/* Justify Content */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">수평 정렬 (justify-content)</h3>
<div className="space-y-2">
<div className="flex justify-start gap-2 bg-gray-100 p-4 rounded">
<div className="bg-green-500 text-white px-4 py-2 rounded">시작</div>
<div className="bg-green-500 text-white px-4 py-2 rounded">정렬</div>
</div>
<div className="flex justify-center gap-2 bg-gray-100 p-4 rounded">
<div className="bg-green-500 text-white px-4 py-2 rounded">중앙</div>
<div className="bg-green-500 text-white px-4 py-2 rounded">정렬</div>
</div>
<div className="flex justify-end gap-2 bg-gray-100 p-4 rounded">
<div className="bg-green-500 text-white px-4 py-2 rounded">끝</div>
<div className="bg-green-500 text-white px-4 py-2 rounded">정렬</div>
</div>
<div className="flex justify-between bg-gray-100 p-4 rounded">
<div className="bg-green-500 text-white px-4 py-2 rounded">양쪽</div>
<div className="bg-green-500 text-white px-4 py-2 rounded">끝</div>
<div className="bg-green-500 text-white px-4 py-2 rounded">정렬</div>
</div>
</div>
</div>
{/* Align Items */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">수직 정렬 (align-items)</h3>
<div className="flex gap-4">
<div className="flex items-start bg-gray-100 p-4 rounded h-32 flex-1">
<div className="bg-purple-500 text-white px-4 py-2 rounded">상단</div>
</div>
<div className="flex items-center bg-gray-100 p-4 rounded h-32 flex-1">
<div className="bg-purple-500 text-white px-4 py-2 rounded">중앙</div>
</div>
<div className="flex items-end bg-gray-100 p-4 rounded h-32 flex-1">
<div className="bg-purple-500 text-white px-4 py-2 rounded">하단</div>
</div>
</div>
</div>
{/* Flex Direction */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">방향 설정</h3>
<div className="grid grid-cols-2 gap-4">
<div className="flex flex-row gap-2 bg-gray-100 p-4 rounded">
<div className="bg-orange-500 text-white p-2 rounded">가로</div>
<div className="bg-orange-500 text-white p-2 rounded">방향</div>
</div>
<div className="flex flex-col gap-2 bg-gray-100 p-4 rounded">
<div className="bg-orange-500 text-white p-2 rounded">세로</div>
<div className="bg-orange-500 text-white p-2 rounded">방향</div>
</div>
</div>
</div>
{/* Flex Grow/Shrink */}
<div>
<h3 className="text-lg font-semibold mb-3">유연한 크기 조절</h3>
<div className="flex gap-2 bg-gray-100 p-4 rounded">
<div className="flex-none bg-red-500 text-white p-4 rounded">
고정 크기
</div>
<div className="flex-1 bg-red-500 text-white p-4 rounded">
flex-1 (남은 공간 채우기)
</div>
<div className="flex-none bg-red-500 text-white p-4 rounded">
고정 크기
</div>
</div>
</div>
</div>
)
}
### Grid 레이아웃 구축하기
Grid는 2차원 레이아웃을 만드는 가장 강력한 CSS 기능입니다. "2차원"이라는 것은 가로와 세로 두 방향을 동시에 제어할 수 있다는 뜻입니다. Grid를 사용하면 복잡한 레이아웃도 쉽게 만들 수 있습니다.
Grid vs Flexbox 언제 어떤 것을 사용할까요?
| 네비게이션 메뉴 | Flexbox | 한 줄로 배치하는 간단한 레이아웃 |
| 카드 갤러리 | Grid | 여러 행과 열로 구성된 격자 레이아웃 |
| 전체 페이지 레이아웃 | Grid | 헤더, 사이드바, 메인, 푸터 등 복잡한 구조 |
| 요소 중앙 정렬 | Flexbox | 간단하고 직관적 |
Grid의 핵심 개념:
- Grid Container: grid 클래스를 적용한 부모 요소
- Grid Items: Grid Container 안에 있는 자식 요소들
- Grid Lines: 격자를 나누는 선들
- Grid Columns: 세로 열
- Grid Rows: 가로 행
주요 Tailwind Grid 클래스들:
- grid: 요소를 Grid Container로 만듭니다
- grid-cols-3: 3개의 열로 나눕니다
- col-span-2: 해당 요소가 2개의 열을 차지합니다
- gap-4: 격자 사이에 간격을 추가합니다
export default function GridLayout() {
return (
<div className="p-8">
<h2 className="text-2xl font-bold mb-6">Grid 레이아웃 예제</h2>
{/* 기본 그리드 */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">기본 그리드 (3열)</h3>
<div className="grid grid-cols-3 gap-4">
<div className="bg-indigo-500 text-white p-4 rounded text-center">1</div>
<div className="bg-indigo-500 text-white p-4 rounded text-center">2</div>
<div className="bg-indigo-500 text-white p-4 rounded text-center">3</div>
<div className="bg-indigo-500 text-white p-4 rounded text-center">4</div>
<div className="bg-indigo-500 text-white p-4 rounded text-center">5</div>
<div className="bg-indigo-500 text-white p-4 rounded text-center">6</div>
</div>
</div>
{/* 반응형 그리드 */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">반응형 그리드</h3>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{[1,2,3,4,5,6,7,8].map(num => (
<div key={num} className="bg-teal-500 text-white p-8 rounded text-center">
{num}
</div>
))}
</div>
</div>
{/* 불규칙한 그리드 */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">불규칙한 레이아웃</h3>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-2 bg-pink-500 text-white p-8 rounded">
2칸 차지
</div>
<div className="bg-pink-500 text-white p-8 rounded">1칸</div>
<div className="bg-pink-500 text-white p-8 rounded">1칸</div>
<div className="bg-pink-500 text-white p-8 rounded">1칸</div>
<div className="col-span-3 bg-pink-500 text-white p-8 rounded">
3칸 차지
</div>
<div className="col-span-4 bg-pink-600 text-white p-8 rounded">
전체 너비 (4칸)
</div>
</div>
</div>
{/* 복잡한 레이아웃 */}
<div>
<h3 className="text-lg font-semibold mb-3">복잡한 대시보드 레이아웃</h3>
<div className="grid grid-cols-6 gap-4">
<div className="col-span-6 md:col-span-4 bg-gray-800 text-white p-8 rounded">
메인 콘텐츠 영역
</div>
<div className="col-span-6 md:col-span-2 bg-gray-700 text-white p-8 rounded">
사이드바
</div>
<div className="col-span-6 md:col-span-2 bg-gray-600 text-white p-8 rounded">
위젯 1
</div>
<div className="col-span-6 md:col-span-2 bg-gray-600 text-white p-8 rounded">
위젯 2
</div>
<div className="col-span-6 md:col-span-2 bg-gray-600 text-white p-8 rounded">
위젯 3
</div>
</div>
</div>
</div>
)
}
### 호버, 포커스, 애니메이션 효과
Tailwind CSS는 상태 변화와 애니메이션을 위한 다양한 유틸리티를 제공합니다. 이러한 효과들은 사용자 경험을 크게 향상하며, 웹사이트를 더욱 생동감 있게 만듭니다.
상태 변화의 핵심 개념
**상태 변경자(State Modifiers)**는 특정 조건에서만 스타일이 적용되도록 하는 Tailwind의 강력한 기능입니다:
- hover: 마우스를 올렸을 때
- focus: 키보드나 마우스로 선택했을 때
- active: 클릭하는 순간
- group-hover: 부모 요소에 마우스를 올렸을 때
트랜지션의 중요성
트랜지션은 상태 변화가 부드럽게 일어나도록 하는 효과입니다. 트랜지션 없이는 변화가 갑작스럽게 나타나서 어색해 보일 수 있습니다:
// ❌ 트랜지션 없음 - 갑작스러운 변화
<button className="bg-blue-500 hover:bg-blue-700">버튼</button>
// ✅ 트랜지션 있음 - 부드러운 변화
<button className="bg-blue-500 hover:bg-blue-700 transition-colors duration-300">버튼</button>
주요 클래스 정리표
🎨 호버 효과 클래스들
| 클래스 | 효과 | 사용 |
| hover:bg-blue-600 | 배경색 변경 | 버튼 색상 변화 |
| hover:scale-110 | 크기 확대/축소 | 카드 확대 효과 |
| hover:shadow-xl | 그림자 변화 | 카드 들어올리기 |
| hover:rotate-6 | 회전 | 이미지 기울이기 |
| hover:translate-y-1 | 위치 이동 | 버튼 눌림 효과 |
⚡ 트랜지션 클래스들
| 클래스 | 의미 | 사용 |
| transition-colors | 색상 변화만 부드럽게 | 버튼, 링크 |
| transition-transform | 크기/위치 변화만 | 호버 확대 효과 |
| transition-all | 모든 변화 부드럽게 | 복합적인 효과 |
| duration-300 | 0.3초 동안 | 일반적인 속도 |
| duration-700 | 0.7초 동안 | 느린 애니메이션 |
🎭 애니메이션 클래스들
| 클래스 | 효과 | 사용 |
| animate-spin | 계속 회전 | 로딩 스피너 |
| animate-ping | 반복 확대 | 알림 표시 |
| animate-pulse | 깜빡임 | 로딩 상태 |
| animate-bounce | 튕김 | 관심 끌기 |
실전 예제
export default function InteractiveEffects() {
return (
<div className="p-8">
<h2 className="text-2xl font-bold mb-6">인터랙티브 효과 종합</h2>
{/* 기본 호버 효과들 */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">기본 호버 효과</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<button className="bg-blue-500 hover:bg-blue-700 text-white p-4 rounded transition-colors duration-300">
색상 변경
</button>
<button className="bg-green-500 text-white p-4 rounded hover:scale-110 transition-transform duration-300">
크기 확대
</button>
<button className="bg-purple-500 text-white p-4 rounded hover:shadow-xl transition-shadow duration-300">
그림자 효과
</button>
<button className="bg-red-500 text-white p-4 rounded hover:rotate-3 transition-transform duration-300">
회전 효과
</button>
</div>
</div>
{/* Group 호버 - 부모 호버시 자식들도 변화 */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">Group 호버 (부모-자식 연동)</h3>
<div className="group bg-white p-6 rounded-lg border hover:shadow-lg transition-all duration-300 cursor-pointer">
<h4 className="text-xl font-bold group-hover:text-blue-500 transition-colors duration-300">
카드 제목
</h4>
<p className="text-gray-600 group-hover:text-gray-800 transition-colors duration-300 mt-2">
마우스를 올리면 제목과 내용이 모두 변합니다.
</p>
<div className="mt-4 h-1 bg-gray-200 rounded overflow-hidden">
<div className="h-full bg-blue-500 w-0 group-hover:w-full transition-all duration-500"></div>
</div>
</div>
</div>
{/* 포커스 효과 */}
<div className="mb-8">
<h3 className="text-lg font-semibold mb-3">포커스 효과 (접근성 중요!)</h3>
<div className="space-y-4">
<input
type="text"
placeholder="포커스 시 테두리 변화"
className="w-full p-3 border-2 border-gray-300 rounded focus:border-blue-500 focus:outline-none transition-colors duration-200"
/>
<input
type="text"
placeholder="포커스 시 링 효과"
className="w-full p-3 border rounded focus:ring-4 focus:ring-blue-200 focus:outline-none transition-all duration-200"
/>
</div>
</div>
{/* 애니메이션 예시 */}
<div>
<h3 className="text-lg font-semibold mb-3">연속 애니메이션</h3>
<div className="flex flex-wrap gap-4">
<div className="flex items-center gap-2">
<div className="animate-spin w-6 h-6 border-2 border-blue-500 border-t-transparent rounded-full"></div>
<span>로딩중...</span>
</div>
<div className="flex items-center gap-2">
<div className="animate-ping w-4 h-4 bg-green-500 rounded-full"></div>
<span>새 알림</span>
</div>
<div className="flex items-center gap-2">
<div className="animate-pulse w-4 h-4 bg-gray-400 rounded"></div>
<span>대기중</span>
</div>
<div className="flex items-center gap-2">
<div className="animate-bounce w-4 h-4 bg-yellow-500 rounded"></div>
<span>주목!</span>
</div>
</div>
</div>
</div>
)
}
### 커스텀 설정과 확장
Tailwind CSS는 프로젝트의 요구사항에 맞게 커스터마이징할 수 있습니다. tailwind.config.js 파일을 수정하여 커스텀 색상, 폰트, 간격 등을 추가할 수 있습니다:
// tailwind.config.js 예시
module.exports = {
content: [
'./pages/**/*.{js,jsx}',
'./components/**/*.{js,jsx}',
'./app/**/*.{js,jsx}',
],
theme: {
extend: {
colors: {
'brand-blue': '#1e40af',
'brand-purple': '#6b21a8',
},
fontFamily: {
'korean': ['Noto Sans KR', 'sans-serif'],
},
spacing: {
'128': '32rem',
'144': '36rem',
},
animation: {
'slide-in': 'slideIn 0.5s ease-out',
},
keyframes: {
slideIn: {
'0%': { transform: 'translateX(-100%)' },
'100%': { transform: 'translateX(0)' },
}
}
},
},
plugins: [],
}
커스텀 설정을 활용한 컴포넌트 예시:
export default function CustomTailwind() {
return (
<div className="p-8">
<h2 className="text-2xl font-bold mb-6 font-korean">
커스텀 Tailwind 설정 활용
</h2>
<div className="space-y-4">
<div className="bg-brand-blue text-white p-6 rounded">
커스텀 색상 (brand-blue) 사용
</div>
<div className="bg-brand-purple text-white p-6 rounded">
커스텀 색상 (brand-purple) 사용
</div>
<div className="animate-slide-in bg-gray-200 p-6 rounded">
커스텀 애니메이션 (slide-in) 적용
</div>
<div className="w-128 bg-gray-300 p-6 rounded">
커스텀 간격 (w-128 = 32rem) 사용
</div>
</div>
</div>
)
}
### 실습: 완전한 반응형 네비게이션 바
지금까지 배운 모든 내용을 종합하여 실용적인 반응형 내비게이션 바를 만들어봅시다:
export default function ComprehensiveWebsite() {
return (
<div className="min-h-screen bg-gray-50">
{/* Fixed 네비게이션 - Position + 반응형 + 호버 */}
<nav className="fixed top-0 left-0 right-0 bg-white shadow-lg z-50 transition-all duration-300">
<div className="max-w-7xl mx-auto px-4">
<div className="flex justify-between items-center h-16">
{/* 로고 - Flexbox */}
<div className="flex items-center gap-2">
<div className="w-8 h-8 bg-blue-500 rounded animate-pulse"></div>
<span className="text-xl font-bold">TechSite</span>
</div>
{/* 데스크톱 메뉴 - 반응형 */}
<div className="hidden md:flex items-center gap-6">
<a href="#" className="hover:text-blue-500 transition-colors duration-200">홈</a>
<a href="#" className="hover:text-blue-500 transition-colors duration-200">서비스</a>
<a href="#" className="hover:text-blue-500 transition-colors duration-200">소개</a>
<button className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 hover:scale-105 transition-all duration-300">
시작하기
</button>
</div>
{/* 모바일 메뉴 버튼 */}
<button className="md:hidden p-2 hover:bg-gray-100 rounded transition-colors duration-200">
<div className="w-6 h-0.5 bg-gray-600 mb-1 transition-transform duration-300"></div>
<div className="w-6 h-0.5 bg-gray-600 mb-1"></div>
<div className="w-6 h-0.5 bg-gray-600"></div>
</button>
</div>
</div>
</nav>
{/* 메인 콘텐츠 - Fixed 네비 때문에 padding-top */}
<main className="pt-16">
{/* Hero 섹션 - Flexbox + 애니메이션 */}
<section className="relative bg-gradient-to-r from-blue-600 to-purple-700 text-white py-20">
{/* 배경 애니메이션 요소들 - Absolute */}
<div className="absolute top-10 left-10 w-20 h-20 bg-white bg-opacity-10 rounded-full animate-bounce"></div>
<div className="absolute bottom-10 right-10 w-32 h-32 bg-white bg-opacity-5 rounded-full animate-pulse"></div>
<div className="max-w-7xl mx-auto px-4 text-center relative z-10">
<h1 className="text-4xl md:text-6xl font-bold mb-6 transform transition-all duration-1000">
최고의 웹 서비스
</h1>
<p className="text-xl md:text-2xl mb-8 text-blue-100">
혁신적인 기술로 여러분의 비즈니스를 성장시키세요
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<button className="bg-white text-blue-600 px-8 py-3 rounded-lg hover:shadow-xl hover:scale-105 transition-all duration-300 font-semibold">
무료 체험
</button>
<button className="border-2 border-white px-8 py-3 rounded-lg hover:bg-white hover:text-blue-600 transition-all duration-300">
더 알아보기
</button>
</div>
</div>
</section>
{/* Sticky 섹션 헤더 */}
<div className="sticky top-16 bg-white border-b z-40 py-4">
<div className="max-w-7xl mx-auto px-4">
<h2 className="text-2xl font-bold text-gray-800">우리의 서비스</h2>
</div>
</div>
{/* 서비스 카드 섹션 - Grid + 호버 효과 */}
<section className="py-16">
<div className="max-w-7xl mx-auto px-4">
{/* 반응형 Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{/* 카드 1 - Group 호버 효과 */}
<div className="group relative bg-white rounded-xl shadow-lg hover:shadow-2xl transition-all duration-500 overflow-hidden">
{/* 절대 위치 배지 */}
<div className="absolute top-4 right-4 bg-red-500 text-white text-xs px-2 py-1 rounded-full z-10">
인기
</div>
<div className="h-48 bg-gradient-to-br from-green-400 to-green-600 relative">
<div className="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-20 transition-all duration-300"></div>
</div>
<div className="p-6">
<h3 className="text-xl font-bold mb-3 group-hover:text-green-500 transition-colors duration-300">
웹 개발
</h3>
<p className="text-gray-600 mb-4 group-hover:text-gray-800 transition-colors duration-300">
현대적이고 반응형인 웹사이트를 제작합니다.
</p>
<button className="w-full bg-green-500 text-white py-2 rounded hover:bg-green-600 transform hover:scale-105 transition-all duration-300">
자세히 보기
</button>
</div>
</div>
{/* 카드 2 */}
<div className="group relative bg-white rounded-xl shadow-lg hover:shadow-2xl transition-all duration-500 overflow-hidden">
<div className="absolute top-4 right-4 bg-blue-500 text-white text-xs px-2 py-1 rounded-full animate-ping">
신규
</div>
<div className="h-48 bg-gradient-to-br from-blue-400 to-blue-600"></div>
<div className="p-6">
<h3 className="text-xl font-bold mb-3 group-hover:text-blue-500 transition-colors duration-300">
모바일 앱
</h3>
<p className="text-gray-600 mb-4 group-hover:text-gray-800 transition-colors duration-300">
iOS와 Android를 위한 네이티브 앱을 개발합니다.
</p>
<button className="w-full bg-blue-500 text-white py-2 rounded hover:bg-blue-600 transform hover:scale-105 transition-all duration-300">
자세히 보기
</button>
</div>
</div>
{/* 카드 3 */}
<div className="group relative bg-white rounded-xl shadow-lg hover:shadow-2xl transition-all duration-500 overflow-hidden md:col-span-2 lg:col-span-1">
<div className="h-48 bg-gradient-to-br from-purple-400 to-purple-600"></div>
<div className="p-6">
<h3 className="text-xl font-bold mb-3 group-hover:text-purple-500 transition-colors duration-300">
클라우드
</h3>
<p className="text-gray-600 mb-4 group-hover:text-gray-800 transition-colors duration-300">
안전하고 확장 가능한 클라우드 솔루션을 제공합니다.
</p>
<button className="w-full bg-purple-500 text-white py-2 rounded hover:bg-purple-600 transform hover:scale-105 transition-all duration-300">
자세히 보기
</button>
</div>
</div>
</div>
</div>
</section>
{/* 통계 섹션 - Flexbox + 애니메이션 */}
<section className="bg-gray-900 text-white py-16">
<div className="max-w-7xl mx-auto px-4">
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 text-center">
<div className="group cursor-pointer">
<div className="text-4xl font-bold text-blue-400 group-hover:scale-125 transition-transform duration-300">
500+
</div>
<div className="text-gray-300 mt-2">완료된 프로젝트</div>
</div>
<div className="group cursor-pointer">
<div className="text-4xl font-bold text-green-400 group-hover:scale-125 transition-transform duration-300">
98%
</div>
<div className="text-gray-300 mt-2">고객 만족도</div>
</div>
<div className="group cursor-pointer">
<div className="text-4xl font-bold text-purple-400 group-hover:scale-125 transition-transform duration-300">
24/7
</div>
<div className="text-gray-300 mt-2">고객 지원</div>
</div>
<div className="group cursor-pointer">
<div className="text-4xl font-bold text-yellow-400 group-hover:scale-125 transition-transform duration-300">
5년
</div>
<div className="text-gray-300 mt-2">경험</div>
</div>
</div>
</div>
</section>
</main>
{/* Fixed 플로팅 버튼 - Position + 애니메이션 */}
<button className="fixed bottom-6 right-6 bg-blue-500 text-white w-14 h-14 rounded-full shadow-lg hover:bg-blue-600 hover:scale-110 transition-all duration-300 z-50 flex items-center justify-center group">
<span className="text-2xl group-hover:animate-bounce">💬</span>
</button>
{/* Fixed 위로가기 버튼 */}
<button className="fixed bottom-6 left-6 bg-gray-800 text-white w-12 h-12 rounded-full shadow-lg hover:bg-gray-700 hover:scale-110 transition-all duration-300 z-50 flex items-center justify-center">
<span className="text-lg">↑</span>
</button>
</div>
)
}
## 결론
Tailwind CSS의 고급 기능들을 활용하면 복잡한 레이아웃과 인터랙티브 한 UI를 쉽게 구현할 수 있습니다. 이번 챕터에서 우리는 반응형 디자인 시스템, Flexbox와 Grid를 활용한 레이아웃 구성, 호버와 포커스 같은 상태 효과, 애니메이션, 그리고 커스텀 설정 방법까지 배웠습니다.
Tailwind CSS의 진정한 강점은 이 모든 기능들을 조합하여 사용할 수 있다는 점입니다. 반응형 접두사는 모든 유틸리티 클래스와 함께 사용할 수 있고, 호버나 포커스 같은 상태 변경자도 마찬가지입니다. 이러한 조합을 통해 매우 복잡한 디자인도 간단한 클래스명으로 구현할 수 있습니다.
다음 챕터부터는 React의 핵심 개념인 컴포넌트에 대해 배워보겠습니다. Tailwind CSS와 React 컴포넌트를 함께 사용하면 재사용 가능하고 유지보수가 쉬운 UI를 만들 수 있습니다!
'학습자료 > Next.js 초보자 학습 과정' 카테고리의 다른 글
| # Next.js 가이드 / 챕터 10: 첫 번째 컴포넌트 만들기 (1) | 2025.08.12 |
|---|---|
| # Next.js 가이드 / 챕터 9: Components - 레고 블록처럼 조립하기 (4) | 2025.08.11 |
| # Next.js 가이드 / 챕터 7: Tailwind CSS 시작하기 (2) | 2025.08.09 |
| # Next.js 가이드 / 챕터 6: Global CSS로 전체 스타일 관리하기 (4) | 2025.08.09 |
| # Next.js 가이드 / 챕터 5: CSS 기초 - 웹페이지에 스타일 입히기 (6) | 2025.08.08 |