Next.js + Tailwind CSS 스타일 관리 가이드

odada·2024년 12월 31일
1

next.js

목록 보기
3/12

Next.js 프로젝트에서 Tailwind CSS를 사용할 때 효율적으로 스타일을 관리하는 방법을 알아보겠습니다.

목차

  1. 자주 사용하는 스타일 상수화
  2. 조건부 스타일링
  3. @apply 디렉티브 활용
  4. 컴포넌트별 스타일 관리
  5. 반응형 디자인

1. 자주 사용하는 스타일 상수화

자주 사용되는 Tailwind 클래스 조합을 상수로 관리하면 재사용성과 일관성을 높일 수 있습니다.

// styles/common.ts
export const tw = {
  // 레이아웃
  container: 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8',
  section: 'py-12 sm:py-16',
  
  // 플렉스 박스
  flexCenter: 'flex items-center justify-center',
  flexBetween: 'flex items-center justify-between',
  
  // 카드
  card: 'bg-white rounded-lg shadow-md p-6',
  
  // 버튼
  buttonPrimary: 'bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded',
  buttonSecondary: 'bg-gray-100 hover:bg-gray-200 text-gray-800 font-semibold py-2 px-4 rounded'
}

사용 예시:

import { tw } from '@/styles/common'

export default function Header() {
  return (
    <header className={`${tw.flexBetween} ${tw.container} h-16`}>
      <Logo />
      <Nav />
    </header>
  )
}

2. 조건부 스타일링

clsx나 cn 유틸리티 함수를 사용하여 조건부 스타일링을 깔끔하게 처리할 수 있습니다.

// lib/utils.ts
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
// components/Button.tsx
import { cn } from '@/lib/utils'
import { tw } from '@/styles/common'

interface ButtonProps {
  variant?: 'primary' | 'secondary'
  className?: string
  children: React.ReactNode
}

export default function Button({ 
  variant = 'primary', 
  className,
  children 
}: ButtonProps) {
  return (
    <button
      className={cn(
        variant === 'primary' ? tw.buttonPrimary : tw.buttonSecondary,
        className
      )}
    >
      {children}
    </button>
  )
}

3. @apply 디렉티브 활용

복잡한 스타일 조합은 @apply 디렉티브를 사용하여 추상화할 수 있습니다.

/* app/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .btn-primary {
    @apply bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded;
  }
  
  .card-hover {
    @apply hover:shadow-lg transition-shadow duration-200;
  }
  
  .input-field {
    @apply w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500;
  }
}

4. 컴포넌트별 스타일 관리

각 컴포넌트 내부에서 스타일을 객체로 관리하여 가독성을 높일 수 있습니다.

// components/ProductCard.tsx
export default function ProductCard() {
  const styles = {
    wrapper: 'relative overflow-hidden rounded-lg',
    image: 'w-full h-48 object-cover',
    content: 'p-4',
    title: 'text-lg font-semibold mb-2',
    price: 'text-green-600 font-bold',
    badge: 'absolute top-2 right-2 bg-red-500 text-white px-2 py-1 rounded-full text-sm'
  }

  return (
    <div className={styles.wrapper}>
      <img src="product.jpg" className={styles.image} alt="Product" />
      <div className={styles.content}>
        <h3 className={styles.title}>Product Name</h3>
        <p className={styles.price}>$99.99</p>
      </div>
      <span className={styles.badge}>Sale</span>
    </div>
  )
}

5. 반응형 디자인

반응형 디자인을 위한 브레이크포인트를 상수로 관리할 수 있습니다.

// styles/screens.ts
export const screens = {
  sm: '640px',
  md: '768px',
  lg: '1024px',
  xl: '1280px',
  '2xl': '1536px',
} as const

export const mediaQueries = {
  sm: `@media (min-width: ${screens.sm})`,
  md: `@media (min-width: ${screens.md})`,
  lg: `@media (min-width: ${screens.lg})`,
  xl: `@media (min-width: ${screens.xl})`,
  '2xl': `@media (min-width: ${screens['2xl']})`,
}

스타일 관리 베스트 프랙티스

  1. 일관성 유지

    • 프로젝트 전체에서 동일한 스타일링 패턴 사용
    • 공통 스타일은 상수로 관리
    • 네이밍 컨벤션 통일
  2. 모듈화

    • 재사용 가능한 스타일은 common.ts로 분리
    • 컴포넌트별 스타일은 컴포넌트 내부에서 관리
    • 복잡한 스타일은 @apply로 추상화
  3. 유지보수성

    • 의미 있는 클래스명 사용
    • 스타일 그룹화와 주석 활용
    • 조건부 스타일링은 cn/clsx 활용
  4. 성능 최적화

    • 불필요한 클래스 중복 제거
    • tailwind-merge로 클래스 최적화
    • 동적 클래스는 조건부로 추가

결론

Tailwind CSS를 사용하면서 스타일을 체계적으로 관리하기 위해서는 적절한 추상화와 구조화가 필요합니다. 위에서 소개한 방법들을 프로젝트의 특성에 맞게 조합하여 사용하면 효율적인 스타일 관리가 가능합니다.

0개의 댓글