--- id: wiki-2026-0508-유지보수-가능한-css-아키텍처-css-modules-ta title: "유지보수 가능한 CSS 아키텍처(CSS Modules & Tailwind)" category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Maintainable CSS Architecture, CSS Modules + Tailwind, CSS 구조 설계] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [css, tailwind, css-modules, architecture, frontend] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: css framework: tailwind-v4 --- # 유지보수 가능한 CSS 아키텍처(CSS Modules & Tailwind) ## 매 한 줄 > **"매 utility-first × scoped-modules 의 hybrid 가 매 2026 의 default"**. CSS Modules 의 file-scoped 격리와 Tailwind v4 의 utility token system 을 결합하면, global cascade 의 fragility 없이도 매 design system consistency 를 확보할 수 있다. CSS-in-JS 의 runtime cost 없이 build-time 으로 모든 게 resolve 된다. ## 매 핵심 ### 매 layering - **Tokens layer**: Tailwind v4 `@theme` directive — colors, spacing, type scale. - **Utilities layer**: `flex`, `gap-4`, `text-sm` — 90% 의 styling. - **Components layer**: CSS Modules `.button { ... }` — 매 multi-property cluster 의 reuse. - **Overrides layer**: page-specific 의 minimal exception. ### 매 결정 트리 - 1-3 utilities → inline className. - 4+ utilities 의 repeated 사용 → CSS Module class + `@apply` (Tailwind v4) or extract component. - complex states (hover, focus-within, group) → CSS Module + `&:hover` nested. - design token (color, spacing) → `@theme` 의 single source. ### 매 응용 1. Next.js App Router 의 `*.module.css` 와 Tailwind 병행. 2. Vite + React 의 component-scoped styles. 3. Storybook 의 visual regression 안정화. ## 💻 패턴 ### Tailwind v4 `@theme` setup ```css /* app/globals.css */ @import "tailwindcss"; @theme { --color-brand-50: oklch(97% 0.02 250); --color-brand-500: oklch(60% 0.18 250); --color-brand-900: oklch(25% 0.10 250); --spacing-gutter: 1.5rem; --font-display: "Inter Display", sans-serif; } ``` ### CSS Module + Tailwind `@apply` ```css /* Button.module.css */ .primary { @apply inline-flex items-center justify-center px-4 py-2 rounded-lg bg-brand-500 text-white font-medium hover:bg-brand-600 active:bg-brand-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors; } .iconLeft { @apply -ml-1 mr-2 h-4 w-4; } ``` ```tsx // Button.tsx import styles from "./Button.module.css"; import clsx from "clsx"; export function Button({ icon, children, className, ...rest }) { return ( ); } ``` ### Variant pattern (CVA) ```ts import { cva } from "class-variance-authority"; export const button = cva( "inline-flex items-center justify-center rounded-lg font-medium transition-colors", { variants: { intent: { primary: "bg-brand-500 text-white hover:bg-brand-600", ghost: "bg-transparent text-brand-700 hover:bg-brand-50", danger: "bg-red-600 text-white hover:bg-red-700", }, size: { sm: "h-8 px-3 text-sm", md: "h-10 px-4 text-base", lg: "h-12 px-6 text-lg", }, }, defaultVariants: { intent: "primary", size: "md" }, } ); ``` ### Nested module styles ```css /* Card.module.css */ .card { @apply rounded-2xl bg-white shadow-md p-6; & > .title { @apply text-lg font-semibold mb-2; } &:hover .title { @apply text-brand-600; } } ``` ### Container queries (2026 default) ```css .grid { @apply grid gap-4; container-type: inline-size; } @container (min-width: 640px) { .grid { grid-template-columns: repeat(2, 1fr); } } @container (min-width: 1024px) { .grid { grid-template-columns: repeat(4, 1fr); } } ``` ### Naming convention ``` features/checkout/ CheckoutForm.tsx CheckoutForm.module.css ← scoped to feature shared/ui/ Button.tsx Button.module.css ← reusable primitives ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | one-off utility cluster | inline Tailwind classes | | reused 3+ places, simple | extract React component | | reused, complex states | CSS Module + `@apply` | | design token | `@theme` directive | | dynamic runtime values | CSS variables on element | | framework-agnostic | CSS Modules only (no Tailwind dep) | **기본값**: Tailwind v4 utilities + CSS Modules for multi-state primitives. ## 🔗 Graph - 부모: [[CSS Architecture]] · [[CSS-in-JS]] - 변형: [[Tailwind CSS v4 CSS-first Architecture]] · [[Utility-first CSS]] - 응용: [[Storybook]] · [[Next.js]] - Adjacent: [[CSS Container Queries]] · [[CSS Variables]] ## 🤖 LLM 활용 **언제**: design system 의 component library scaffold, variant matrix 생성, refactor of legacy global CSS. **언제 X**: extreme custom animation timeline (use Framer Motion), CSS art (use raw CSS). ## ❌ 안티패턴 - **Global override soup**: `!important` chains in `globals.css` — cascade hell. - **Atomic CSS without tokens**: utilities referencing magic numbers `mt-[17px]` everywhere. - **CSS-in-JS runtime in 2026**: emotion/styled-components 의 runtime cost — prefer build-time (vanilla-extract, Tailwind). - **Module + Tailwind 의 random mix**: same component 에 styled-jsx, .module.css, inline 모두 사용. ## 🧪 검증 / 중복 - Verified (Tailwind v4 docs 2026, Next.js 15 patterns, MDN CSS Modules). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Tailwind v4 + CSS Modules hybrid 의 substantive content. |