본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 9장: 커스텀 변형과 플러그인 시스템
2026년 3월 3일·웹 개발·

9장: 커스텀 변형과 플러그인 시스템

Tailwind CSS v4의 @custom-variant, @plugin 디렉티브, CSS 기반 확장 시스템, 그리고 기존 JS 플러그인에서의 마이그레이션을 실전 중심으로 다룹니다.

9분506자5개 섹션
frontend
공유
tailwind-v49 / 11
1234567891011
이전8장: 다크 모드와 테마 전략다음10장: 디자인 시스템 구축 실전

8장에서 다크 모드와 테마 전략을 배웠습니다. 이 장에서는 Tailwind CSS v4의 확장 시스템을 다룹니다. @custom-variant로 커스텀 변형을 정의하고, @plugin으로 JavaScript 플러그인을 연결하며, 프로젝트에 맞는 확장을 구축하는 방법을 살펴봅니다.

@custom-variant: 커스텀 변형 정의

기본 사용법

@custom-variant는 CSS 선택자를 기반으로 새로운 변형을 정의합니다.

커스텀 변형 기본
css
/* 다크 모드 변형 (8장에서 다룸) */
@custom-variant dark (&:where(.dark, .dark *));
 
/* RTL(오른쪽에서 왼쪽) 변형 */
@custom-variant rtl (&:where([dir="rtl"], [dir="rtl"] *));
 
/* 인쇄 미디어 변형 */
@custom-variant print {
  @media print {
    &
  }
}

&는 실제 선택자가 대체될 위치를 나타냅니다.

커스텀 변형 사용
html
<!-- RTL 레이아웃 대응 -->
<div class="ml-4 rtl:mr-4 rtl:ml-0">RTL 대응 여백</div>
 
<!-- 인쇄 시 스타일 -->
<nav class="flex gap-4 print:hidden">네비게이션</nav>
<article class="print:text-black print:bg-white">인쇄용 콘텐츠</article>

미디어 쿼리 기반 변형

미디어 쿼리 변형
css
/* 모션 선호도 */
@custom-variant motion-safe {
  @media (prefers-reduced-motion: no-preference) {
    &
  }
}
 
@custom-variant motion-reduce {
  @media (prefers-reduced-motion: reduce) {
    &
  }
}
 
/* 고대비 모드 */
@custom-variant high-contrast {
  @media (prefers-contrast: more) {
    &
  }
}
 
/* 가로/세로 방향 */
@custom-variant landscape {
  @media (orientation: landscape) {
    &
  }
}
 
@custom-variant portrait {
  @media (orientation: portrait) {
    &
  }
}

상태 기반 변형

상태 기반 변형
css
/* 로딩 상태 */
@custom-variant loading (&:where([data-loading], [data-loading] *));
 
/* 인증 상태 */
@custom-variant authenticated (&:where([data-authenticated], [data-authenticated] *));
 
/* 에디터 모드 */
@custom-variant editing (&:where([data-editing], [data-editing] *));
상태 변형 사용
html
<body data-loading>
  <div class="loading:opacity-50 loading:pointer-events-none">
    로딩 중 비활성화
  </div>
  <div class="loading:block hidden">
    로딩 스피너
  </div>
</body>
 
<main data-editing>
  <div class="editing:ring-2 editing:ring-primary editing:ring-dashed">
    편집 모드에서 테두리 표시
  </div>
</main>
Tip

커스텀 변형은 프로젝트의 상태 관리 패턴과 긴밀하게 연결됩니다. data-* 속성을 상태 표현에 사용하면, JavaScript의 상태 변경이 CSS 변형으로 자연스럽게 반영됩니다. React에서는 data-loading={isLoading || undefined}처럼 조건부로 속성을 추가합니다.

복합 변형

여러 조건을 결합한 변형도 정의할 수 있습니다.

복합 변형
css
/* 다크 모드 + 고대비 */
@custom-variant dark-high-contrast {
  @media (prefers-contrast: more) {
    &:where(.dark, .dark *)
  }
}
 
/* 터치 디바이스 */
@custom-variant touch {
  @media (hover: none) and (pointer: coarse) {
    &
  }
}
 
/* 마우스 디바이스 */
@custom-variant mouse {
  @media (hover: hover) and (pointer: fine) {
    &
  }
}
디바이스 기반 스타일
html
<!-- 터치에서는 더 큰 터치 타겟 -->
<button class="p-2 touch:p-4 touch:text-lg">
  클릭/탭
</button>
 
<!-- 마우스에서만 hover 효과 -->
<div class="mouse:hover:shadow-lg mouse:hover:scale-105 transition">
  카드
</div>

@plugin: JavaScript 플러그인 연결

CSS만으로 해결하기 어려운 복잡한 확장은 @plugin 디렉티브로 JavaScript 플러그인을 연결합니다.

@plugin 사용
css
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@plugin "./plugins/custom-components.js";

공식 플러그인

@tailwindcss/typography

산문(prose) 콘텐츠에 타이포그래피 스타일을 적용합니다.

typography 플러그인
css
@plugin "@tailwindcss/typography";
prose 사용
html
<article class="prose prose-lg dark:prose-invert max-w-none">
  <h1>블로그 포스트 제목</h1>
  <p>마크다운이나 CMS에서 생성된 HTML 콘텐츠에
  자동으로 타이포그래피 스타일이 적용됩니다.</p>
  <pre><code>console.log('코드 블록도 스타일링됩니다');</code></pre>
</article>

@tailwindcss/forms

폼 요소의 기본 스타일을 개선합니다.

forms 플러그인
css
@plugin "@tailwindcss/forms";
스타일된 폼
html
<input type="text" class="rounded-md border-border" placeholder="텍스트 입력" />
<select class="rounded-md border-border">
  <option>옵션 1</option>
  <option>옵션 2</option>
</select>
<input type="checkbox" class="rounded text-primary" />

커스텀 플러그인 작성

v4에서도 JavaScript 플러그인 API는 여전히 사용 가능합니다.

plugins/custom-components.js
javascript
import plugin from 'tailwindcss/plugin';
 
export default plugin(function ({ addComponents, addUtilities, theme }) {
  addComponents({
    '.skeleton': {
      'background': `linear-gradient(90deg,
        ${theme('colors.neutral.200')} 25%,
        ${theme('colors.neutral.300')} 50%,
        ${theme('colors.neutral.200')} 75%)`,
      'background-size': '200% 100%',
      'animation': 'skeleton-loading 1.5s ease-in-out infinite',
      'border-radius': theme('borderRadius.md'),
    },
  });
 
  addUtilities({
    '.scrollbar-thin': {
      'scrollbar-width': 'thin',
    },
    '.scrollbar-none': {
      'scrollbar-width': 'none',
      '&::-webkit-scrollbar': {
        'display': 'none',
      },
    },
  });
});
플러그인 연결
css
@import "tailwindcss";
@plugin "./plugins/custom-components.js";
Info

v4의 플러그인 API는 v3과 대부분 호환됩니다. addBase(), addComponents(), addUtilities(), matchUtilities() 등의 함수를 동일하게 사용할 수 있습니다. 다만, 간단한 확장은 CSS의 @utility나 @layer를 사용하는 것이 더 간결합니다.

CSS vs JavaScript 확장 선택 기준

상황권장 방식
단순 유틸리티 클래스 추가@utility (CSS)
커스텀 변형 정의@custom-variant (CSS)
정적 컴포넌트 스타일@layer components (CSS)
다크 모드/테마 변형@custom-variant (CSS)
동적 값 기반 유틸리티matchUtilities() (JS Plugin)
복잡한 기본 스타일 (typography)@plugin (JS Plugin)
서드파티 플러그인 사용@plugin (JS Plugin)
CSS 우선 접근
css
/* 대부분의 확장은 CSS로 충분 */
@import "tailwindcss";
 
/* 커스텀 변형 */
@custom-variant dark (&:where(.dark, .dark *));
@custom-variant rtl (&:where([dir="rtl"], [dir="rtl"] *));
 
/* 커스텀 유틸리티 */
@utility scrollbar-hidden {
  scrollbar-width: none;
  &::-webkit-scrollbar { display: none; }
}
 
@utility text-balance {
  text-wrap: balance;
}
 
/* 커스텀 컴포넌트 */
@layer components {
  .btn { /* ... */ }
  .card { /* ... */ }
}
 
/* 복잡한 플러그인만 JS로 */
@plugin "@tailwindcss/typography";

프리셋(Presets)

여러 프로젝트에서 공유할 설정을 프리셋으로 패키징할 수 있습니다.

프리셋 파일 (preset.css)
css
@theme {
  --color-brand: oklch(0.60 0.22 250);
  --color-brand-light: oklch(0.80 0.12 250);
  --color-brand-dark: oklch(0.40 0.24 252);
 
  --font-sans: "Pretendard Variable", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", monospace;
 
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
}
 
@custom-variant dark (&:where(.dark, .dark *));
 
@utility text-balance {
  text-wrap: balance;
}
프리셋 사용
css
@import "tailwindcss";
@import "./preset.css";
 
/* 프로젝트별 추가 설정 */
@theme {
  --color-accent: oklch(0.70 0.20 330);
}

정리

Tailwind CSS v4의 확장 시스템은 CSS 우선(CSS-first) 철학을 따릅니다. @custom-variant로 커스텀 변형을, @utility로 커스텀 유틸리티를, @layer components로 컴포넌트 스타일을 정의합니다. 복잡한 동적 확장이 필요한 경우에만 @plugin으로 JavaScript 플러그인을 연결합니다. 이 접근법은 도구 체인을 단순화하고, CSS 도구와의 호환성을 최대화합니다.

다음 장에서는 지금까지 배운 모든 기능을 종합하여 실전 디자인 시스템을 구축합니다. 토큰 설계, 컴포넌트 라이브러리, 테마 시스템, 그리고 팀 공유를 위한 구조화 전략을 다룹니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#frontend

관련 글

웹 개발

10장: 디자인 시스템 구축 실전

Tailwind CSS v4로 프로덕션 디자인 시스템을 구축합니다. 토큰 계층 설계, 컴포넌트 라이브러리, 테마 시스템, 접근성, 팀 협업 전략을 실전 중심으로 다룹니다.

2026년 3월 5일·10분
웹 개발

8장: 다크 모드와 테마 전략

Tailwind CSS v4의 다크 모드 전략, CSS 커스텀 프로퍼티 기반 런타임 테마 전환, 다중 테마 패턴, 그리고 next-themes와의 통합을 실전 중심으로 다룹니다.

2026년 3월 1일·10분
웹 개발

11장: v3에서 v4로 마이그레이션

Tailwind CSS v3에서 v4로의 마이그레이션 가이드 — 주요 변경사항, 자동 마이그레이션 도구, 단계별 전환 전략, 그리고 흔한 문제 해결법을 다룹니다.

2026년 3월 7일·13분
이전 글8장: 다크 모드와 테마 전략
다음 글10장: 디자인 시스템 구축 실전

댓글

목차

약 9분 남음
  • @custom-variant: 커스텀 변형 정의
    • 기본 사용법
    • 미디어 쿼리 기반 변형
    • 상태 기반 변형
    • 복합 변형
  • @plugin: JavaScript 플러그인 연결
    • 공식 플러그인
      • @tailwindcss/typography
      • @tailwindcss/forms
    • 커스텀 플러그인 작성
  • CSS vs JavaScript 확장 선택 기준
  • 프리셋(Presets)
  • 정리