Tailwind CSS 종합 가이드
TailwindCSS Vite 설정 방법 (v 4.1)
1. install
npm install tailwindcss @tailwindcss/vite

2. vite.config.js setting
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), tailwindcss()],
});

3. index.css import tailwindCSS
@import 'tailwindcss';
4. tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}


5. custom utility
@import url("https://fonts.googleapis.com/css2?family=Funnel+Display:wght@300..800&display=swap");
@import "tailwindcss";
@theme {
--color-primary: #030412;
--color-midnight: #06091f;
--color-navy: #161a31;
--color-indigo: #1f1e39;
--color-storm: #282b4b;
--color-aqua: #33c2cc;
--color-mint: #57db96;
--color-royal: #5c33cc;
--color-lavender: #7a57db;
--color-fuchsia: #ca2f8c;
--color-orange: #cc6033;
--color-sand: #d6995c;
--color-coral: #ea4884;
--animate-orbit: orbit 50s linear infinite;
@keyframes orbit {
0% {
transform: rotate(calc(var(--angle) * 1deg))
translateY(calc(var(--radius) * 1px)) rotate(calc(var(--angle) * -1deg));
}
100% {
transform: rotate(calc(var(--angle) * 1deg + 360deg))
translateY(calc(var(--radius) * 1px))
rotate(calc((var(--angle) * -1deg) - 360deg));
}
}
--animate-marquee: marquee 50s linear infinite;
--animate-marquee-vertical: marquee-vertical 50s linear infinite;
@keyframes marquee {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
@keyframes marquee-vertical {
from {
transform: translateY(0);
}
to {
transform: translateY(calc(-100% - var(--gap)));
}
}
}
body {
background: #030412;
font-family: "Funnel Display", sans-serif;
color: white;
scroll-behavior: smooth;
overflow-x: hidden;
}
.c-space {
@apply sm:px-10 px-5 lg:px-15;
}
.hover-animation {
@apply hover:-translate-y-1 duration-200;
}
.section-spacing {
@apply min-h-screen mt-20 md:mt-30;
}
.text-heading {
@apply font-bold text-3xl md:text-4xl;
}
.headtext {
@apply mt-2 mb-2 text-xl;
}
.subtext {
@apply text-neutral-400 text-sm md:text-base text-pretty;
}
/* Navigation */
.nav-ul {
@apply flex flex-col items-center gap-4 sm:flex-row md:gap-6 relative z-20;
}
.nav-li {
@apply text-neutral-400 hover:text-white max-sm:w-full max-sm:rounded-md py-2 max-sm:px-5;
}
.nav-link {
@apply text-lg md:text-base hover:text-white transition-colors;
}
/* Button Components */
.btn {
@apply relative px-1 py-4 text-sm text-center rounded-full font-extralight bg-primary w-[12rem] cursor-pointer overflow-hidden;
}
/* About Section */
.grid-1 {
@apply row-span-2 md:col-span-3 h-[15rem] md:h-full relative overflow-hidden hover:-translate-y-1 duration-200;
}
.grid-2 {
@apply row-span-1 md:col-span-3 h-[15rem] md:h-full relative overflow-hidden hover:-translate-y-1 duration-200;
}
.grid-3 {
@apply row-span-1 md:col-span-3 h-[15rem] md:h-full relative overflow-hidden hover:-translate-y-1 duration-200;
}
.grid-4 {
@apply row-span-1 md:col-span-2 h-[15rem] md:h-full relative overflow-hidden hover:-translate-y-1 duration-200;
}
.grid-5 {
@apply row-span-1 md:col-span-4 h-[15rem] md:h-full relative overflow-hidden hover:-translate-y-1 duration-200;
}
.grid-default-color {
@apply p-6 bg-gradient-to-b from-storm to-indigo rounded-2xl;
}
.grid-special-color {
@apply p-6 bg-gradient-to-b from-royal to-lavender rounded-2xl;
}
.grid-black-color {
@apply p-6 bg-gradient-to-tl from-[#3A3A3A] via-[#242424] to-[#3A3A3A] rounded-2xl;
}
/* Contact Section*/
.field-label {
@apply text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70;
}
.field-input {
@apply w-full min-h-10 rounded-md px-3 py-2 text-sm bg-white/10 transition duration-200 placeholder-neutral-500 border border-white/10 mt-2;
}
.field-input-focus {
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20;
}
섹션 1: 유틸리티 우선 패러다임: 근본적인 전환
Tailwind CSS는 단순한 CSS 단축키 모음이 아니라, 개발자가 스타일링에 접근하는 방식을 근본적으로 바꾸는 철학적 전환을 제시합니다. 이 섹션에서는 Tailwind CSS의 핵심 철학을 정립하고, 전통적인 방법론과 비교하여 그 독특한 가치 제안을 조명하며, 초기에 제기되는 일반적인 비판들을 심도 있게 다룹니다.
1.1. "유틸리티 우선" 해부하기: 인라인 스타일을 넘어서
Tailwind CSS의 핵심은 미리 정의된 단일 목적 클래스(유틸리티 클래스)를 HTML에 직접 적용하여 요소를 스타일링하는 것입니다. 언뜻 보기에 이는 인라인 스타일과 유사해 보일 수 있지만, 근본적인 차이점이 존재합니다. 인라인 스타일과 달리 유틸리티 우선 접근법은 몇 가지 결정적인 이점을 제공합니다.
첫째, 미리 정의된 디자인 시스템 내에서 스타일을 선택함으로써 제약 조건 하에서 디자인하게 됩니다. 이는 인라인 스타일에서 흔히 발생하는 임의의 "매직 넘버" 사용을 방지하고 시각적 일관성을 구축하는 데 훨씬 용이합니다.
둘째, 인라인 스타일에서는 미디어 쿼리를 사용할 수 없지만, Tailwind의 반응형 유틸리티를 사용하면 완전한 반응형 인터페이스를 쉽게 구축할 수 있습니다.
셋째, :hover나 :focus와 같은 상태(state)는 인라인 스타일로 타겟팅할 수 없지만, Tailwind의 상태 변형(state variants)을 사용하면 이러한 상태를 유틸리티 클래스로 손쉽게 스타일링할 수 있습니다.
이러한 차이점들은 유틸리티 우선 접근법이 단순히 스타일을 HTML에 넣는 행위를 넘어선다는 것을 보여줍니다. 이는 본질적으로 잘 정의된 디자인 시스템을 API처럼 활용하는 방식입니다. 개발자는 CSS 속성을 직접 작성하는 대신, 디자인 시스템이 제공하는 토큰(token)과 규칙을 호출합니다. 이 시스템은 시각적 일관성을 강제하는 제약 조건을 부과하며, 이는 프로젝트가 성장함에 따라 그 가치가 더욱 빛을 발합니다.
1.2. 핵심 장점: 속도, 제약, 그리고 유지보수성
Tailwind CSS를 채택함으로써 얻을 수 있는 주요 이점은 개발 속도, 디자인 일관성, 그리고 코드 유지보수성의 향상으로 요약할 수 있습니다.
- 개발 속도: 개발자는 더 이상 HTML과 CSS 파일을 번갈아 가며 작업할 필요가 없으며, 'sidebar-inner-wrapper'와 같은 의미 없는 클래스 이름을 고안하는 데 드는 인지적 부하에서 해방됩니다. 이로 인해 프로토타이핑과 개발 과정이 현저하게 빨라집니다.
- 제약 기반의 일관성: Tailwind는 색상, 간격, 타이포그래피 등 제한된 디자인 토큰 세트를 기반으로 합니다. 이는 대규모 팀이나 장기 프로젝트에서 발생할 수 있는 시각적 불일치를 줄이고, 전체 애플리케이션에 걸쳐 통일된 시각적 언어를 장려합니다.
- 안전성과 유지보수성: 전통적인 CSS는 전역적(global) 성격을 띠기 때문에, 한 곳에서의 변경이 예기치 않은 다른 곳의 스타일을 깨뜨릴 위험이 항상 존재합니다. 반면, HTML에 적용된 유틸리티 클래스는 해당 요소에만 영향을 미치는 지역적(local) 범위에 머뭅니다. 따라서 변경 사항이 훨씬 안전하며, 의도치 않은 부작용에 대한 걱정 없이 스타일을 수정할 수 있습니다. 또한, 유틸리티는 재사용성이 매우 높기 때문에 새로운 기능을 추가할 때마다 CSS 파일이 계속해서 커지는 문제를 방지할 수 있습니다.
이 접근법의 가장 명백한 단점은 HTML 마크업이 길고 복잡해진다는 점, 즉 "클래스 이름의 폭주(class name conundrum)"입니다. 하지만 이는 결함이라기보다는 의도된 아키텍처적 트레이드오프로 이해해야 합니다. 복잡성이 추상적이고 깨지기 쉬운 CSS 캐스케이드(cascade)에서 구체적이고 지역적인 범위의 HTML 마크업으로 이동한 것입니다. 바로 이 지역성(locality)이 장기적으로 유지보수를 더 쉽게 만드는 핵심 요인입니다.
1.3. 비교 분석: Tailwind CSS 대 전통적 방법론 (BEM)
Tailwind의 유틸리티 우선 접근법은 BEM(Block, Element, Modifier)과 같은 의미론적(semantic), 컴포넌트 기반 방법론과 뚜렷한 대조를 이룹니다. BEM은 CSS 내에서 캡슐화되고 재사용 가능한 컴포넌트를 만들기 위해 체계적인 이름 규칙에 초점을 맞춥니다. 반면, Tailwind는 HTML 내에서 스타일을 조합(composition)하는 데 중점을 둡니다.
BEM의 가장 큰 난제는 "이름 짓기"의 어려움과 팀 전체에 걸쳐 일관성을 유지하는 것입니다. 반면 Tailwind의 단점은 자체 클래스 이름에 대한 학습 곡선과 잠재적인 HTML의 복잡성입니다.
이 두 방법론의 차이는 "관심사 분리(Separation of Concerns)" 원칙을 어떻게 해석하는지에서 비롯됩니다. 전통적인 CSS와 BEM은 HTML(구조), CSS(표현), JS(동작)를 별도의 파일에 두어 관심사를 분리하는 것을 옹호합니다. Tailwind는 표현(클래스)을 구조(HTML)에 혼합함으로써 이 원칙을 위반한다는 비판을 받기도 합니다.
하지만 현대 웹 개발은 컴포넌트 기반으로 패러다임이 전환되었습니다. 여기서 진정한 관심사의 단위는 파일이 아니라, 자체적으로 구조, 표현, 동작을 캡슐화하는 컴포넌트입니다. 이러한 관점에서 볼 때, Tailwind는 관심사 분리를 위반하는 것이 아니라 오히려 컴포넌트를 중심으로 재정의합니다. 스타일링 로직(클래스)을 컴포넌트 파일 내의 HTML 구조와 함께 배치함으로써(co-location), 컴포넌트의 캡슐화를 강화하고, 이를 독립적이고 이식 가능한 UI 단위로 만듭니다. 이는 React나 Vue와 같은 현대 프레임워크의 철학과 완벽하게 일치하는, 보다 현대적인 원칙의 해석입니다.
| 특성 | Tailwind CSS | BEM (Block, Element, Modifier) |
| 철학 | 유틸리티 우선 (Utility-First) | 의미론적 컴포넌트 (Semantic Component) |
| 스타일 단위 | 단일 목적의 원자적 클래스 | 블록, 요소, 수정자 기반의 클래스 |
| 조합의 위치 | HTML 마크업 | CSS 파일 |
| 주요 장점 | 빠른 개발 속도, 일관성, CSS 파일 크기 최소화 | 명확한 구조, 높은 재사용성, CSS의 완전한 활용 |
| 주요 단점 | HTML 마크업의 복잡성 증가, 클래스 이름 학습 곡선 | 클래스 이름 짓기의 어려움, 장황한 클래스 이름 |
| 이상적 사용 사례 | 빠른 프로토타이핑, 디자인 시스템 기반 프로젝트, 컴포넌트 기반 프레임워크 | 대규모의 고도로 구조화된 애플리케이션, 순수 CSS/Sass 프로젝트 |
1.4. 성능 프로필: JIT 컴파일과 초고도 최적화 빌드
Tailwind의 성능은 단순한 부가 기능이 아니라 핵심적인 설계 목표입니다. 이는 JIT(Just-In-Time) 컴파일러라는 강력한 빌드 도구를 통해 달성됩니다. JIT 엔진은 HTML, JavaScript 등 프로젝트의 소스 파일을 스캔하여 실제로 사용된 클래스만을 식별하고, 최종 CSS 파일에 포함시킵니다. "퍼징(purging)"이라고도 불리는 이 프로세스를 통해, 대규모 프로젝트에서도 최종 프로덕션 CSS 번들 크기는 종종 10kB 미만으로 유지됩니다.
여기서 중요한 점은, 이러한 성능상의 이점이 자동으로 주어지는 것이 아니라는 사실입니다. 이는 개발자가 빌드 프로세스를 올바르게 구성했을 때 얻을 수 있는 설계된 결과물입니다. 개발 과정에서는 수천 개의 유틸리티 클래스를 활용하여 최대한의 유연성을 누리지만, 이 모든 것을 프로덕션에 그대로 배포한다면 성능 재앙이 될 것입니다. JIT 컴파일러는 이 개발 경험과 프로덕션 결과물 사이의 중요한 다리 역할을 합니다.
따라서 Tailwind의 성능을 마스터한다는 것은 빌드 구성을 마스터하는 것과 동의어입니다. tailwind.config.js 파일의 content 경로를 정확하게 설정하는 것이 무엇보다 중요합니다. 이 경로 설정이 잘못되면, 필요한 스타일이 실수로 제거되거나, 최악의 경우 사용되지 않는 방대한 양의 CSS가 그대로 프로덕션에 포함될 수 있습니다. 그러므로 개발자는 이 구성이 올바르게 작동하는지 반드시 확인하고 검증해야 합니다.
섹션 2: 정밀한 반응형 인터페이스 구축
이 섹션에서는 Tailwind의 모바일 우선 접근법과 강력한 중단점(breakpoint) 시스템을 중심으로, 반응형 디자인을 구현하는 실용적인 가이드를 제공합니다.
2.1. 모바일 우선 워크플로우 수용
Tailwind는 기본적으로 모바일 우선(mobile-first) 중단점 시스템을 사용합니다. 이는 접두사가 없는 유틸리티(예: w-16)가 모든 화면 크기(모바일 포함)에 적용되고, 접두사가 붙은 유틸리티(예: md:w-32)는 해당 중단점 이상의 화면 크기에서만 적용된다는 것을 의미합니다. (CSS @midea( min-width:)와 같습니다. 의미론적 방법론에서는 보통 @media (max-width:)를 사용해서 데스크탑을 기준으로 설계합니다. )
이러한 접근 방식에서 초보자들이 가장 흔하게 겪는 함정은 모바일 화면을 타겟팅하기 위해 sm: 접두사를 사용하는 것입니다. 그러나 sm:은 "작은 화면에서만"을 의미하는 것이 아니라, "작은 중단점(small breakpoint) 이상에서"를 의미합니다. 따라서 모바일 기기를 위한 스타일은 접두사가 없는 기본 유틸리티를 사용해야 합니다. 이 워크플로우는 개발자가 견고한 모바일 기반을 먼저 구축한 다음, 더 큰 화면을 위해 점진적으로 복잡성을 추가하도록 유도합니다.
<div class="sm:text-center"></div>
<div class="text-center md:text-left"></div>
2.2. 중단점 활용: 기본값부터 사용자 정의 구성까지
Tailwind는 일반적인 기기 해상도에서 영감을 받은 5개의 기본 중단점을 제공합니다.
| 중단점 접두사 | 최소 너비 | 동등한 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 v3에서는 tailwind.config.js 파일의 theme.screens 객체를 통해, v4에서는 CSS 파일 내 @theme 변수를 통해 중단점을 추가, 수정 또는 제거할 수 있습니다.
사용자 정의 중단점을 정의할 때는 일관된 단위를 사용하는 것이 매우 중요합니다. 예를 들어, 기본 중단점이 rem 단위를 사용하는데 px 단위의 사용자 정의 중단점을 추가하면, CSS 생성 시 예기치 않은 순서로 정렬되어 스타일 재정의(override) 문제가 발생할 수 있습니다. 예측 가능하고 안정적인 반응형 시스템을 유지하기 위해서는 모든 중단점 값에 대해 동일한 단위를 고수하는 것이 핵심적인 기술 지침입니다.
2.3. 고급 기법: 특정 중단점 범위 타겟팅
때로는 특정 중단점 범위 내에서만 스타일을 적용해야 할 필요가 있습니다. 전통적인 CSS에서는 @media (min-width: 768px) and (max-width: 1023px)와 같은 복잡한 미디어 쿼리를 작성해야 합니다. 이는 장황하고, 중단점 값이 변경될 경우 오류가 발생하기 쉽습니다.
Tailwind는 min-width 접두사(예: md:)와 max-width 수정자(예: max-lg:)를 조합하여 이 문제를 선언적으로 해결합니다. 예를 들어, md:max-lg:flex 클래스는 md 중단점부터 lg 중단점 직전까지의 범위에서만 display: flex를 적용합니다.
이 접근 방식은 CSS의 복잡성을 효과적으로 추상화합니다. 개발자는 구현 세부 사항 대신 "중간 크기와 큰 크기 사이에서 이 스타일을 적용하라"는 의도를 선언합니다. 이는 유지보수성에 중대한 영향을 미칩니다. 만약 설정 파일에서 lg 중단점의 값을 변경하면, max-lg: 수정자는 자동으로 새로운 값을 참조하게 됩니다. 개발자는 더 이상 모든 미디어 쿼리를 일일이 찾아다니며 수정할 필요가 없습니다. 이는 Tailwind의 도구가 어떻게 더 높은 수준의 추상화를 제공하여 유지보수 비용을 줄이고, 반응형 디자인 시스템을 더욱 견고하고 유연하게 만드는지를 보여주는 대표적인 사례입니다.
<div class="md:max-xl:flex">
</div>
섹션 3: 동적이고 상호작용적인 UI 구현
이 섹션에서는 전통적으로 복잡한 CSS나 JavaScript가 필요했던 부모-자식 및 형제 요소 간의 상호작용을 중심으로, Tailwind의 상태 변형(state variants)을 사용하여 UI에 생동감을 불어넣는 방법을 탐구합니다.
3.1. 상태 변형 마스터하기: hover, focus, active 등
Tailwind에서는 모든 유틸리티 클래스에 상태 변형 접두사를 붙여 조건부로 적용할 수 있습니다. 예를 들어, hover:bg-sky-700은 마우스를 올렸을 때 배경색을 변경하고, focus:ring은 요소가 포커스를 받았을 때 링(ring) 효과를 추가합니다.
이러한 상태 변형은 반응형 접두사와 결합(stacking)하여 더욱 구체적이고 문맥에 맞는 스타일을 만들 수 있습니다. 예를 들어, md:hover:bg-fuchsia-600은 md 중단점 이상의 화면에서 요소에 마우스를 올렸을 때만 배경색을 변경합니다.
이 방식은 전통적인 CSS와 대조적입니다. 전통적인 CSS에서는 .btn:hover와 같이 하나의 클래스 정의에 여러 의사 클래스(pseudo-class)를 연결합니다. 반면 Tailwind는 각 상태에 대해 별도의 조합 가능한 클래스를 사용하는 접근 방식을 취하며, 이는 스타일을 원자적인 조각들로 구축한다는 유틸리티 우선 철학과 일맥상통합니다.
<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>
3.2. 부모 상태 기반 스타일링: group과 group-hover의 힘
순수 CSS만으로는 부모 요소의 상태(예: :hover)에 따라 자식 요소의 스타일을 변경하는 것이 까다롭습니다. 이를 해결하기 위해 종종 JavaScript를 사용해야 했습니다. Tailwind는 group 유틸리티를 통해 이 문제를 선언적으로 해결합니다.
부모 요소에 group 클래스를 추가하면, 그 자식 요소들에서 group-* 형태의 변형(예: group-hover)을 사용하여 부모의 상태에 따라 스타일을 지정할 수 있습니다. 예를 들어, 아래 카드 예제에서 부모인 <a> 태그에 마우스를 올리면(group 클래스 보유), 자식인 <svg>와 <h3>의 색상이 group-hover:text-white에 의해 변경됩니다.
<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>
이 group 유틸리티는 JavaScript 없이도 복잡한 상호작용을 구현할 수 있는 깔끔하고 선언적인 API를 제공합니다. 또한, 중첩된 상호작용 요소를 처리하기 위해 group/{name}과 같이 그룹에 이름을 지정하여 특정 부모 그룹의 상태에만 반응하도록 할 수도 있습니다.
3.3. 형제 상태 기반 스타일링: peer와 peer-checked를 활용한 상호작용 폼
peer 유틸리티는 group과 유사하지만, 부모-자식 관계가 아닌 형제(sibling) 요소 간의 상호작용을 다룹니다. <input>과 같은 요소에 peer 클래스를 추가하면, 그 다음에 오는 형제 요소에서 peer-* 변형(예: peer-checked, peer-invalid)을 사용하여 스타일을 지정할 수 있습니다.
이 기능은 CSS의 일반 형제 결합자(~)에 대한 직접적인 매핑입니다. 예를 들어, <label>에 적용된 peer-checked:text-blue-500 클래스는 CSS에서 input:checked ~ label { color: blue; }와 거의 동일하게 변환됩니다. peer 유틸리티의 핵심 제약 사항은 상태를 감지할 peer 요소가 스타일을 적용받을 요소보다 DOM 구조상 앞에 위치해야 한다는 것입니다. 이는 CSS 형제 결합자의 단방향성(forward-only)을 반영합니다.
peer는 이러한 CSS 선택자 구문을 "나의 피어가 체크되었을 때"와 같이 관계 기반의 높은 수준으로 추상화하여, 개발자가 더 쉽게 코드를 이해하고 작성할 수 있도록 돕습니다. 이는 특히 커스텀 체크박스나 라디오 버튼과 같은 UI 패턴을 만들 때 매우 유용합니다.
<div class="flex items-center">
<input id="checkbox" type="checkbox" class="peer...">
<label for="checkbox" class="ml-2 peer-checked:text-blue-500">
Click me
</label>
</div>
더 나아가, peer는 :has() 의사 클래스의 동작을 부분적으로, 미래 지향적으로 모방하는 역할을 합니다. :has()는 요소가 특정 자식이나 형제를 "가지고 있는지" 여부에 따라 스타일을 적용할 수 있어 매우 강력하지만, 모든 브라우저에서 지원되지는 않습니다. peer는 :has()의 모든 기능을 대체할 수는 없지만, 커스텀 폼 컨트롤과 같은 일반적인 UI 패턴의 상당 부분을 매우 선언적이고 이해하기 쉬운 방식으로 해결합니다. 이는 복잡한 CSS를 작성하거나 JavaScript 상태 관리에 의존할 필요성을 줄여줍니다.
섹션 4: 고급 테마 설정: 다크 모드 심층 분석
이 섹션에서는 다크 모드를 구현하는 두 가지 주요 전략을 다루고, 각 전략의 사용 시기와 사용자 제어 테마 전환기를 구현하는 방법에 대한 명확한 지침을 제공합니다.
4.1. 전략 1: prefers-color-scheme을 이용한 자동 다크 모드
Tailwind의 dark: 변형은 기본적으로 prefers-color-scheme: dark CSS 미디어 쿼리를 사용합니다. 이는 별도의 설정 없이도 사용자의 운영 체제(OS) 설정에 따라 테마가 자동으로 전환되는 "제로-구성(zero-config)" 방식입니다.
이 전략은 수동 전환 기능이 필요 없고 시스템 설정을 따르는 것만으로 충분한 프로젝트에 이상적입니다. JavaScript가 필요 없으며, 간단하고 매끄러운 사용자 경험을 제공합니다.
<div class="bg-white dark:bg-gray-800">
<h1 class="text-gray-900 dark:text-white">Dark Mode Title</h1>
<p class="text-gray-600 dark:text-gray-300">
This component respects the user's system preference for dark mode.
</p>
</div>
4.2. 전략 2: 클래스 기반 전략을 통한 수동 전환
사용자에게 직접 테마를 전환할 수 있는 옵션을 제공하려면, 기본 동작을 재정의해야 합니다. Tailwind v3에서는 tailwind.config.js 파일에 darkMode: 'class'를 설정하여 이를 활성화합니다. v4에서는 CSS 파일 내에서 @custom-variant 지시어를 사용합니다: @custom-variant dark (&:where(.dark,.dark *));.
/* Tailwind v4+ CSS 설정 */
@import "tailwindcss";
@custom-variant dark (&:where(.dark,.dark *));
4.3. 구현 패턴: 상태 관리를 위한 JavaScript
수동 전환 기능을 구현하려면 클라이언트 측 상태 관리가 필수적입니다. 미디어 쿼리 전략은 단순하지만 사용자에게 선택권을 주지 않습니다. 반면 클래스 기반 전략은 완전한 선택권을 제공하지만 JavaScript와 상태 관리라는 복잡성을 동반합니다.
가장 이상적인 패턴은 이 두 가지를 결합한 하이브리드 접근 방식입니다. 즉, 클래스 기반 전략을 사용하되, 초기 상태는 시스템 설정을 기본값으로 따르도록 하는 것입니다. 이를 통해 사용자의 OS 설정을 기본적으로 존중하면서도, 필요에 따라 사용자가 직접 테마를 변경할 수 있는 유연성을 제공합니다.
다음은 완전한 테마 전환기 JavaScript 예제입니다. 이 스크립트는 페이지 로드 시 스타일이 적용되지 않은 콘텐츠가 잠시 나타나는 현상(FOUC, Flash of Unstyled Content)을 방지하기 위해 <head> 태그 안에 인라인으로 배치하는 것이 가장 좋습니다.
// On page load or when changing themes, best to add inline in `head` to avoid FOUC
if (localStorage.theme === 'dark' |
| (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
// 로컬 스토리지에 'dark'가 있거나, 로컬 스토리지가 없고 시스템이 다크 모드일 경우
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
// 사용자가 명시적으로 라이트 모드를 선택할 때 호출하는 함수
function setLightMode() {
localStorage.theme = 'light';
document.documentElement.classList.remove('dark');
}
// 사용자가 명시적으로 다크 모드를 선택할 때 호출하는 함수
function setDarkMode() {
localStorage.theme = 'dark';
document.documentElement.classList.add('dark');
}
// 사용자가 명시적으로 시스템 설정을 따르도록 선택할 때 호출하는 함수
function setSystemMode() {
localStorage.removeItem('theme');
// 시스템 설정에 따라 즉시 테마를 다시 적용
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
이 스크립트는 페이지 로드 시 localStorage에 저장된 테마 설정을 먼저 확인합니다. 설정이 없다면 window.matchMedia를 통해 시스템 설정을 확인하여 기본 테마를 결정합니다. 사용자가 UI의 버튼을 클릭하면 setLightMode, setDarkMode, setSystemMode 함수가 호출되어 localStorage와 <html> 태그의 클래스를 업데이트합니다. 이 하이브리드 패턴은 사용자에게 최상의 경험을 제공하는 견고하고 사용자 친화적인 기능을 구현하는 지름길입니다.
섹션 5: 컴포넌트 추상화와 사용자 정의
Tailwind를 마스터하는 과정에서 가장 중요한 과제 중 하나는 유틸리티 우선 철학을 버리지 않으면서 코드 중복을 관리하고 재사용 가능한 컴포넌트를 만드는 것입니다. 이 섹션에서는 이 문제를 해결하기 위한 전략을 다룹니다.
5.1. @apply 지시어: 컴포넌트 클래스의 신중한 사용
@apply 지시어는 기존 유틸리티 클래스들을 사용자 정의 CSS 규칙 안으로 가져와 인라인으로 적용할 수 있게 해줍니다. 이는 버튼과 같이 공통적으로 반복되는 유틸리티 패턴을 .btn과 같은 재사용 가능한 컴포넌트 클래스로 추출할 때 유용합니다.
예제:
.btn-primary {
@apply bg-blue-500 text-white font-bold py-2 px-4 rounded hover:bg-blue-700;
}
이제 HTML에서는 긴 유틸리티 클래스 목록 대신 .btn-primary 클래스 하나만 사용하면 됩니다.
<button class="btn-primary">
Click me
</button>
5.2. 모범 사례와 함정: @apply의 역설
유틸리티 우선 접근법의 가장 큰 유지보수성 문제는 반복되는 유틸리티 조합을 관리하는 것입니다.
@apply는 이 문제를 해결하는 것처럼 보이지만, 과도하게 사용하면 오히려 전통적인 CSS가 가졌던 문제들(클래스 이름 짓기, 너무 이른 추상화 등)로 회귀할 수 있어 신중하게 사용해야 합니다. 일부 순수주의자들은 이를 안티패턴으로 간주하기도 합니다.
Tailwind의 핵심 철학은 HTML에서의 조합입니다. @apply는 조합의 장소를 다시 CSS로 옮기기 때문에 모순적으로 보일 수 있습니다. 그렇다면 이 지시어는 왜 존재하는 것일까요? 그 전략적 목적은 외부 시스템과의 경계를 다루거나 진정한 의미의 "컴포넌트"를 만들 때 드러납니다.
예를 들어, 개발자가 직접 제어할 수 없는 외부 라이브러리의 스타일을 재정의하거나 , 마크다운으로 생성된 HTML( @tailwindcss/typography 플러그인이 이 개념을 활용)을 스타일링할 때 @apply는 매우 효과적인 "어댑터" 역할을 합니다.
@apply의 함정은 약간의 변형만 있는 간단한 패턴(예: 카드 레이아웃)을 추상화하는 데 사용하는 것입니다. 이런 경우에는 유틸리티 클래스를 props로 받아 동적으로 클래스를 조합하는 JavaScript 프레임워크 컴포넌트(예: React의 <Card> 컴포넌트)를 만드는 것이 유연성을 유지하면서 중복을 관리하는 올바른 방법입니다.
따라서 @apply를 마스터한다는 것은, 간단히 반복되는 패턴(JS 컴포넌트로 처리)과, 정말로 고정되고 복잡한 컴포넌트 또는 외부 통합( @apply로 처리) 사이의 경계를 인식하는 능력에 달려있습니다.
5.3. @layer 지시어를 이용한 사용자 정의 스타일 구성
@layer 지시어는 사용자 정의 스타일을 Tailwind의 base, components, utilities라는 세 개의 "버킷" 중 하나에 그룹화할 수 있게 해줍니다. 이를 통해 사용자 정의 스타일이 올바른 우선순위를 갖게 되어, 예상대로 유틸리티 클래스에 의해 재정의될 수 있도록 보장합니다.
예를 들어, @apply를 사용하여 만든 컴포넌트 클래스는 components 레이어에 배치하는 것이 모범 사례입니다. 이렇게 하면, 해당 컴포넌트에 유틸리티 클래스(예: mt-4)를 추가했을 때, 유틸리티 클래스가 컴포넌트의 기본 스타일보다 높은 우선순위를 가져 예상대로 동작하게 됩니다.
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn-primary {
@apply bg-blue-500 text-white font-bold py-2 px-4 rounded;
}
.btn-primary:hover {
@apply bg-blue-700;
}
}
@layer는 Tailwind의 예측 가능한 캐스케이드 시스템을 깨뜨리지 않으면서 사용자 정의 CSS를 안전하게 통합하기 위한 필수적인 도구입니다.
섹션 6: 플러그인 생태계를 통한 기능 확장
이 섹션에서는 공식 플러그인을 활용하여 일반적이고 복잡한 스타일링 문제를 효율적으로 해결하는 방법을 보여줍니다.
6.1. 제어 불가능한 콘텐츠 스타일링: @tailwindcss/typography
유틸리티 우선 CSS의 주된 난관 중 하나는 CMS나 마크다운 파일에서 생성된 HTML과 같이 개발자가 직접 클래스를 추가할 수 없는 콘텐츠를 스타일링하는 것입니다. @tailwindcss/typography 플러그인은 이 문제를 해결하기 위해 설계되었습니다. 이 플러그인은 prose라는 클래스 세트를 추가하여, "순수" HTML 블록에 아름다운 타이포그래피 기본값을 적용합니다.
콘텐츠를 감싸는 부모 요소에 prose 클래스를 적용하기만 하면, 그 안의 <h1>, <p>, <ul> 등 표준 HTML 요소들이 자동으로 일관되고 가독성 높은 스타일을 갖게 됩니다. 이는 엄청난 개발 시간을 절약해주는 강력한 솔루션입니다.
<article class="prose lg:prose-xl">
<h1>My Blog Post</h1>
<p>This content comes from a headless CMS, and I can't add classes to it directly.</p>
<ul>
<li>But the typography plugin styles it for me.</li>
<li>It's incredibly useful.</li>
</ul>
</article>
6.2. 폼 요소 길들이기: @tailwindcss/forms
브라우저의 기본 폼 요소 스타일은 일관성이 없고 커스터마이징하기 매우 까다롭습니다. @tailwindcss/forms 플러그인은 <input>, <select>, <checkbox>와 같은 폼 요소들의 스타일을 초기화(reset)하여, 유틸리티 클래스로 쉽게 스타일링할 수 있도록 만들어 줍니다.
이 플러그인은 브라우저 간의 비일관적인 기본 스타일을 제거하고, 폼 요소들을 표준화하여 유틸리티 우선 워크플로우를 UI의 모든 부분에 일관되게 적용할 수 있도록 합니다.
<select class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
</select>
<input type="checkbox" class="rounded text-pink-500">
섹션 7: 전문적인 개발 환경 구축
이 마지막 섹션에서는 빌드 프로세스와 코드 품질 자동화에 초점을 맞춰, 견고한 개발 환경을 설정하는 실용적인 단계별 가이드를 제공합니다.
7.1. Tailwind 빌드 프로세스에서 PostCSS의 역할
Tailwind CSS는 근본적으로 PostCSS 플러그인입니다. PostCSS는 JavaScript를 사용하여 CSS를 변환하는 도구입니다. Tailwind 프로젝트에서 PostCSS는 CSS 파일을 처리하면서
@tailwind나 @import "tailwindcss"와 같은 Tailwind 고유의 지시어를 찾아, 이를 실제 생성된 CSS 코드로 대체하는 역할을 합니다.
이 관계를 이해하는 것이 핵심입니다. Tailwind는 마법이 아니라, CSS 빌드 단계의 일부로 실행되는 프로그램입니다. 이는 autoprefixer와 같은 다른 PostCSS 플러그인과 함께 사용될 수 있는 이유를 설명해 줍니다(v4부터는 이 기능이 내장되어 자동 처리됨).
7.2. 구성 심층 분석: postcss.config.js와 tailwind.config.js
postcss.config.js 파일의 역할은 tailwindcss 플러그인을 비롯한 다른 PostCSS 플러그인들을 등록하는 것입니다.
postcss.config.js 예제:
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
반면, tailwind.config.js는 Tailwind 자체의 동작을 제어합니다. 주요 섹션은 다음과 같습니다:
- content: JIT 컴파일러가 스캔할 파일을 지정하는 가장 중요한 부분입니다. 프로덕션 빌드 시 사용되지 않는 스타일을 제거(purge)하는 데 결정적인 역할을 합니다.
- theme.extend: 기본 디자인 시스템을 덮어쓰지 않고 새로운 색상, 글꼴, 중단점 등을 추가할 때 사용합니다.
- plugins: @tailwindcss/forms와 같은 공식 및 커뮤니티 플러그인을 등록합니다.
7.3. 코드 품질 자동화: Prettier와 prettier-plugin-tailwindcss 설정
Tailwind의 가장 큰 단점으로 지적되는 것은 HTML에 길고 순서 없는 클래스 문자열이 나열된다는 점입니다. 이는 인지적 부하를 유발하고, 여러 개발자가 협업할 때 코드 스타일의 비일관성으로 이어질 수 있습니다.
prettier-plugin-tailwindcss는 이 문제를 완벽하게 해결하는 자동화 도구입니다. 이 플러그인은 코드를 저장할 때마다 HTML 내의 유틸리티 클래스들을 권장되는 논리적 순서에 따라 자동으로 정렬해 줍니다.
설치 및 구성:
- npm을 사용하여 개발 의존성으로 설치합니다.
npm install -D prettier prettier-plugin-tailwindcss
- 프로젝트 루트에 .prettierrc 파일을 만들고 플러그인을 추가합니다.
{
"plugins": ["prettier-plugin-tailwindcss"]
}
이 플러그인은 단순한 편의 도구가 아닙니다. 이는 팀 기반 개발 환경에서 반드시 필요한 도구로 간주되어야 합니다. 클래스 순서에 대한 모든 논쟁을 원천적으로 차단하고, 모든 개발자가 일관된 코드 스타일을 유지하도록 강제합니다. 또한, 클래스 순서 변경으로 인한 불필요한 코드 변경 내역(diff)이 발생하지 않아 코드 리뷰가 훨씬 깔끔해집니다. 결과적으로, 이 플러그인은 Tailwind의 가장 큰 약점을 직접적으로 보완하여, 유지보수성과 가독성을 극대화하는 필수적인 부분입니다.
결론
Tailwind CSS는 단순한 CSS 프레임워크를 넘어, 현대 웹 개발의 컴포넌트 중심 패러다임에 부합하는 새로운 스타일링 방법론을 제시합니다. 유틸리티 우선 접근법은 초기 학습 곡선과 HTML 마크업의 복잡성이라는 트레이드오프를 감수하는 대신, 개발 속도의 비약적인 향상, 디자인 시스템 기반의 일관성, 그리고 전역적 CSS의 위험성을 제거한 높은 유지보수성을 제공합니다.
이 가이드에서 살펴보았듯이, Tailwind를 마스터하는 것은 단순히 클래스 이름을 암기하는 것을 의미하지 않습니다. 이는 모바일 우선 반응형 디자인을 체계적으로 구축하고, group 및 peer와 같은 강력한 상태 변형을 활용하여 JavaScript 없이도 동적인 UI를 구현하며, @apply와 같은 도구를 언제, 어떻게 사용해야 하는지에 대한 전략적 판단을 내리는 능력을 포함합니다.
또한, JIT 컴파일러를 통한 성능 최적화, 플러그인 생태계를 통한 기능 확장, 그리고 PostCSS 및 Prettier와 같은 도구를 활용한 전문적인 개발 환경 구축은 Tailwind의 잠재력을 최대한으로 이끌어내는 데 필수적입니다. 특히 prettier-plugin-tailwindcss는 팀 프로젝트에서 코드의 일관성과 가독성을 보장하는 핵심적인 역할을 수행합니다.
궁극적으로 Tailwind CSS는 개발자가 CSS의 복잡한 추상화와 이름 짓기에서 벗어나, 디자인 시스템의 제약 안에서 빠르고 안전하게 UI를 구축하는 데 집중할 수 있도록 지원하는 강력한 도구입니다. 이 가이드에서 다룬 개념과 기법들을 깊이 있게 이해하고 적용함으로써, 개발자는 어떠한 규모의 프로젝트에서도 생산성과 코드 품질을 한 단계 끌어올릴 수 있을 것입니다.
부록: Tailwind CSS vs. 순수 CSS 심층 비교
이 부록은 Tailwind CSS의 유틸리티 우선 접근법이 전통적인 CSS 작성 방식과 어떻게 다른지 구체적인 코드 예시를 통해 명확하게 보여주기 위해 작성되었습니다. 각 섹션에서는 주요 CSS 속성 그룹별로 Tailwind 클래스와 그에 해당하는 순수 CSS 코드를 나란히 비교하여, 개발자가 두 방식의 차이점과 장단점을 직관적으로 이해할 수 있도록 돕습니다.
1. 기본 레이아웃 (Layout)
레이아웃은 웹 페이지 구조의 근간을 이룹니다. Tailwind는 display, position과 같은 핵심 CSS 속성들을 직관적인 클래스로 제공하여 빠르고 일관된 레이아웃 구현을 가능하게 합니다.
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| 블록 요소 | <div class="block">...</div> | .element { display: block; } |
| 인라인 블록 요소 | <div class="inline-block">...</div> | .element { display: inline-block; } |
| Flex 컨테이너 | <div class="flex">...</div> | .container { display: flex; } |
| Grid 컨테이너 | <div class="grid">...</div> | .container { display: grid; } |
| 요소 숨기기 | <div class="hidden">...</div> | .hidden-element { display: none; } |
| 상대 위치 지정 | <div class="relative">...</div> | .element { position: relative; } |
| 절대 위치 지정 | <div class="absolute top-0 left-0">...</div> | .element { position: absolute; top: 0; left: 0; } |
| 고정 위치 지정 | <div class="fixed bottom-0 right-0">...</div> | .element { position: fixed; bottom: 0; right: 0; } |
2. Flexbox와 Grid
Tailwind는 복잡한 Flexbox와 Grid 레이아웃을 선언적으로 쉽게 구축할 수 있는 강력한 유틸리티를 제공합니다. 순수 CSS에서는 여러 속성을 조합해야 하는 작업을 Tailwind에서는 클래스 조합으로 해결합니다.
Flexbox
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| 가로 정렬 (Row) | <div class="flex flex-row">...</div> | .container { display: flex; flex-direction: row; } |
| 세로 정렬 (Column) | <div class="flex flex-col">...</div> | .container { display: flex; flex-direction: column; } |
| 중앙 정렬 | <div class="flex justify-center items-center">...</div> | .container { display: flex; justify-content: center; align-items: center; } |
| 요소 간 간격 | <div class="flex justify-between">...</div> | .container { display: flex; justify-content: space-between; } |
Grid
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| 3열 그리드 | <div class="grid grid-cols-3">...</div> | .grid-container { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); } |
| 열 병합 | <div class="col-span-2">...</div> | .grid-item { grid-column: span 2 / span 2; } |
| 행 병합 | <div class="row-span-3">...</div> | .grid-item { grid-row: span 3 / span 3; } |
| 그리드 간격 | <div class="grid grid-cols-3 gap-4">...</div> | .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } |
3. 간격 (Spacing)
Tailwind의 간격 시스템(padding, margin)은 미리 정의된 스케일을 사용하여 디자인의 일관성을 유지하는 데 큰 도움을 줍니다. p-4는 항상 1rem을 의미하므로, 개발자는 임의의 값을 사용하는 대신 시스템에 정의된 값을 선택하게 됩니다.
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| 전체 패딩 | <div class="p-4">...</div> | .element { padding: 1rem; } |
| 수직/수평 패딩 | <div class="px-4 py-2">...</div> | .element { padding-left: 1rem; padding-right: 1rem; padding-top: 0.5rem; padding-bottom: 0.5rem; } |
| 상단 마진 | <div class="mt-8">...</div> | .element { margin-top: 2rem; } |
| 수평 중앙 정렬 | <div class="mx-auto">...</div> | .element { margin-left: auto; margin-right: auto; } |
4. 크기 (Sizing)
요소의 너비와 높이를 제어하는 유틸리티는 반응형 디자인의 핵심입니다. Tailwind는 고정 값, 백분율, 뷰포트 단위 등 다양한 크기 옵션을 제공합니다.
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| 고정 너비 | <div class="w-64">...</div> | .element { width: 16rem; } |
| 백분율 너비 | <div class="w-1/2">...</div> | .element { width: 50%; } |
| 전체 너비 | <div class="w-full">...</div> | .element { width: 100%; } |
| 화면 높이 | <div class="h-screen">...</div> | .element { height: 100vh; } |
| 최대 너비 | <div class="max-w-md">...</div> | .element { max-width: 28rem; } |
5. 타이포그래피 (Typography)
가독성 높은 텍스트 스타일링을 위한 다양한 유틸리티를 제공합니다. 특히 truncate와 같은 복합 유틸리티는 여러 CSS 속성을 하나로 추상화하여 편의성을 높입니다.
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| 글자 크기 | <p class="text-lg">...</p> | .text { font-size: 1.125rem; line-height: 1.75rem; } |
| 글자 굵기 | <p class="font-bold">...</p> | .text { font-weight: 700; } |
| 글자 색상 | <p class="text-red-500">...</p> | .text { color: #ef4444; } |
| 텍스트 정렬 | <p class="text-center">...</p> | .text { text-align: center; } |
| 이탤릭체 | <p class="italic">...</p> | .text { font-style: italic; } |
| 텍스트 말줄임 | <p class="truncate w-64">...</p> | .truncate-text { width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
6. 배경 및 테두리 (Backgrounds & Borders)
요소의 시각적 모양을 정의하는 핵심적인 부분입니다. 특히 rounded 유틸리티는 다양한 모서리 둥글기 옵션을 제공하여 유연한 디자인을 지원합니다.
배경
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| 배경색 | <div class="bg-blue-500">...</div> | .element { background-color: #3b82f6; } |
| 배경 이미지 (Cover) | <div class="bg-cover" style="background-image: url(...)">...</div> | .element { background-size: cover; background-position: center;... } |
| 배경 이미지 (Contain) | <div class="bg-contain" style="background-image: url(...)">...</div> | .element { background-size: contain; background-position: center;... } |
테두리
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| 기본 테두리 | <div class="border">...</div> | .element { border-width: 1px; } |
| 테두리 두께 및 색상 | <div class="border-4 border-purple-500">...</div> | .element { border-width: 4px; border-color: #8b5cf6; } |
| 특정 방향 테두리 | <div class="border-t-2">...</div> | .element { border-top-width: 2px; } |
| 모서리 둥글기 | <div class="rounded-lg">...</div> | .element { border-radius: 0.5rem; } |
| 완전한 원 | <div class="rounded-full">...</div> | .element { border-radius: 9999px; } |
| 특정 모서리 둥글기 | <div class="rounded-tl-xl rounded-br-xl">...</div> | .element { border-top-left-radius: 0.75rem; border-bottom-right-radius: 0.75rem; } |
7. 상태 및 상호작용 (States & Interactivity)
Tailwind의 가장 강력한 기능 중 하나는 hover, focus와 같은 의사 클래스(pseudo-classes)와 group, peer 같은 특별한 상태 변형(variants)을 통해 JavaScript 없이도 동적인 UI를 구현할 수 있다는 점입니다.
기본 상태
| 기능 | Tailwind CSS 구현 | 순수 CSS 구현 |
| Hover 상태 | <button class="bg-blue-500 hover:bg-blue-700">...</button> | .btn { background-color: #3b82f6; }.btn:hover { background-color: #1d4ed8; } |
| Focus 상태 | <input class="focus:ring-2 focus:ring-blue-300"> | input:focus { box-shadow: 0 0 0 2px #93c5fd; } |
| 반응형 + Hover | <div class="bg-gray-200 md:hover:bg-gray-300">...</div> | .element { background-color: #e5e7eb; } @media (min-width: 768px) {.element:hover { background-color: #d1d5db; } } |
특별 기능: group 및 peer
이 기능들은 순수 CSS의 복잡한 선택자(selector)를 직관적인 클래스 이름으로 추상화하여 코드의 가독성과 유지보수성을 크게 향상시킵니다.
부모 상태 기반 스타일링 (group)
group을 사용하면 부모 요소의 상태에 따라 자식 요소의 스타일을 변경할 수 있습니다. 이는 순수 CSS에서 부모 선택자에 :hover를 적용하고 자손 결합자를 사용하는 것과 동일한 효과를 냅니다.
Tailwind CSS 예제:
<a href="#" class="group block p-6 bg-white hover:bg-sky-500">
<h3 class="text-slate-900 group-hover:text-white">New project</h3>
<p class="text-slate-500 group-hover:text-white">Create a new project.</p>
</a>
순수 CSS 예제:
<a href="#" class="card">
<h3 class="card-title">New project</h3>
<p class="card-description">Create a new project.</p>
</a>
.card:hover.card-title {
color: white;
}
.card:hover.card-description {
color: white;
}
형제 상태 기반 스타일링 (peer)
peer를 사용하면 한 형제 요소(예: input)의 상태에 따라 그 뒤에 오는 다른 형제 요소(예: label)의 스타일을 변경할 수 있습니다. 이는 CSS의 일반 형제 결합자(~)와 :checked 같은 의사 클래스를 사용하는 것과 같습니다.
Tailwind CSS 예제:
<input id="checkbox" type="checkbox" class="peer">
<label for="checkbox" class="ml-2 peer-checked:text-blue-500">
Click me
</label>
순수 CSS 예제:
<input id="checkbox" type="checkbox" class="my-checkbox">
<label for="checkbox" class="my-label">
Click me
</label>
.my-checkbox:checked ~.my-label {
color: #3b82f6;
}
'HTML, CSS > CSS' 카테고리의 다른 글
| 모던 CSS 가이드 (0) | 2025.09.05 |
|---|---|
| TailwindCSS (1) | 2025.02.12 |
| CSS Transition (3) | 2024.12.13 |
| CSS 애니메이션 효과 만들기 및 참고 사이트 (1) | 2024.12.13 |
| CSS 단위별 기준과 특징 (%, px, vh, em, rem) (5) | 2024.12.13 |