클로드 코드로 프론트엔드 코드를 짜다 보면 짜증 나는 순간이 옵니다. 알아서 잘 짜주는 듯하다가도, 어느 순간 Inter 폰트에 보라색 그라데이션을 얹은 흔해 터진 UI를 뱉어냅니다. 지정해 둔 디자인 토큰은 무시하고 bg-[#1e293b] 같은 Hex 코드를 컴포넌트에 직접 박아 넣기도 합니다.
이건 클로드 코드가 멍청해서가 아닙니다. 세션이 시작될 때 컨텍스트를 제대로 못 읽었거나, 테일윈드 CSS v3와 v4 사이에서 갈피를 못 잡고 길을 잃었기 때문입니다. 터미널 기반 에이전트가 내 프로젝트의 스타일 규칙을 억지로 따르게 만드는 세 가지 실무 설정을 정리했습니다.
디자인 토큰을 무시하고 지멋대로 코드를 짜는 이유
클로드 코드는 세션이 열릴 때 프로젝트 루트에 있는 CLAUDE.md를 읽어 들입니다. 그런데 세션 중간에 새로 만든 컴포넌트 하나만 수정하도록 명령하면, 전체 디자인 토큰 파일과의 연결 고리를 놓쳐버립니다. 컨텍스트가 빈약해지면 에이전트는 자기가 학습한 데이터의 평균값, 즉 '어디서 많이 본 듯한 무난한 보라색 웹사이트' 스타일로 돌아갑니다.
테일윈드 v4로 오면서 생긴 구조적 변화도 한몫합니다. v3는 tailwind.config.js 파일의 theme.extend에 자바스크립트 객체로 토큰을 적었습니다. 반면 테일윈드 v4(Oxide 엔진)는 JS 설정 파일을 버리고 메인 CSS 파일 안에서 @theme 지시어로 CSS 변수를 다룹니다. 클로드 코드가 옛날 방식만 생각하고 tailwind.config.js를 찾다가 실패하면, 곧바로 JSX 안에 하드코딩된 값을 주입하기 시작합니다.
/* src/styles/globals.css - Tailwind CSS v4 메인 스타일시트 */
@import "tailwindcss";
@theme {
--color-brand-primary: oklch(0.55 0.22 260);
--color-brand-secondary: oklch(0.75 0.18 150);
--color-surface-card: oklch(0.98 0.01 240);
--font-display: "Fraunces", serif;
--font-body: "Bricolage Grotesque", sans-serif;
--spacing-section: 5rem;
--radius-card: 0.75rem;
}
v4 프로젝트라면 --color-*, --font-* 형태의 CSS 프로퍼티 이름을 스타일시트에 정확히 명시해야 합니다. 그래야 클로드 코드가 이걸 테일윈드 유틸리티 클래스로 바꿉니다. 작업 중간에 CSS 변수를 수정했다면 터미널에 /compact를 치거나 세션을 다시 열어 프롬프트 캐시를 비워줘야 합니다.
뻔한 UI 출력을 틀어막는 CLAUDE.md 작성법
"예쁘게 만들어줘" 같은 모호한 요청은 아무런 도움이 안 됩니다. 절대 쓰지 말아야 할 금지 규칙(Negative Constraints)을 CLAUDE.md에 명확히 적어두어야 합니다. 파일이 너무 길면 AI가 중요한 지침을 놓치므로, 디자인 시스템 관련 규칙은 20행 안팎으로 짧게 잘라 넣습니다.
## Frontend Aesthetics & Design System Rules
### Typography Discipline
- ABSOLUTELY FORBIDDEN: Inter, Roboto, Open Sans, Arial, system-ui default fonts.
- Display Font: Use var(--font-display) / font-display class only.
- Body Font: Use var(--font-body) / font-body class only.
### Color & Token Rules
- ALL colors MUST reference design tokens in src/styles/globals.css.
- ABSOLUTELY FORBIDDEN: Hardcoded Hex (#1a202c), RGB, or HSL values in JSX/TSX.
- ABSOLUTELY FORBIDDEN: Inline style={{ ... }} attributes for layout or color.
- ABSOLUTELY FORBIDDEN: Generic purple-to-blue gradients on white backgrounds.
### Component Directives
- Always reuse primitives from @/components/ui (shadcn/ui registry).
- NEVER hand-roll a new Button, Dialog, or Card if it exists in the registry.
명령어 파일 작성과 함께 외부 도구를 연결하면 규칙이 더 탄탄해집니다.
- 공식 프론트엔드 디자인 플러그인을 설치합니다.
claude plugin install frontend-design@claude-plugins-official - 레퍼런스 사이트에서 OKLCH 색상과 공간 시스템을 추출해 문서로 저장합니다.
npx design.md [https://your-brand-reference.com](https://your-brand-reference.com) .mcp.json에 shadcn/ui MCP 서버를 등록해서 컴포넌트 목록을 직접 조회하게 만듭니다.
{
"mcpServers": {
"shadcn": {
"command": "npx",
"args": ["-y", "@shadcn/mcp-server"]
}
}
}
이렇게 세팅하면 클로드 코드가 마음대로 스타일을 지어내는 대신 DESIGN.md와 MCP 레지스트리를 먼저 뒤적입니다. 지저분하게 꼬인 레이아웃을 사람이 직접 바로잡는 시간을 줄일 수 있습니다.
스타일 위반을 자동으로 잡아내는 검증 스크립트
프롬프트만으로는 복잡한 작업 중에 튀어나오는 w-[317px] 같은 임의 수치나 인라인 스타일을 완벽히 차단하기 어렵습니다. Rust 기반 린터인 Oxlint와 Git Hook을 묶어서 잘못된 코드가 들어오면 스스로 수정하게 만들어야 합니다.
/* .oxlintrc.json */
{
"jsPlugins": ["oxlint-tailwindcss"],
"settings": {
"tailwindcss": {
"entryPoint": "src/styles/globals.css"
}
},
"rules": {
"tailwindcss/no-hardcoded-colors": "error",
"tailwindcss/no-arbitrary-value": "error",
"tailwindcss/prefer-theme-tokens": "error"
}
}
Oxlint를 설정했으면 커밋 직전에 JSX 내부의 인라인 스타일과 Hex 코드를 걸러내는 셸 스크립트를 실행합니다.
#!/usr/bin/env bash
set -e
echo "UI 무결성 및 인라인 스타일 검사 시작..."
INLINE_STYLES=$(git diff --cached -G'style=\{\{' --name-only '*.tsx' '*.jsx' || true)
if [ -n "$INLINE_STYLES" ]; then
echo "ERROR: 다음 파일에 금지된 인라인 style 속성이 포함되어 있습니다:"
echo "$INLINE_STYLES"
exit 1
fi
HARDCODED_HEX=$(git diff --cached -G'#[0-9a-fA-F]{3,6}' --name-only '*.tsx' '*.jsx' | grep -v 'globals.css' || true)
if [ -n "$HARDCODED_HEX" ]; then
echo "ERROR: 다음 파일에 하드코딩된 Hex 컬러 코드가 검출되었습니다:"
echo "$HARDCODED_HEX"
exit 1
fi
echo "UI 무결성 검사 통과."
/* .lintstagedrc.json */
{
"*.{jsx,tsx,ts,js}": [
"oxlint --config .oxlintrc.json",
"bash scripts/verify-ui-integrity.sh"
]
}
검사에서 에러(Exit Code 1)가 떨어지면 클로드 코드는 이 로그를 에러로 인식합니다. 그리고 곧바로 코드를 쳐다보며 Hex 값을 CSS 변수 토큰으로 스스로 바꿔놓습니다.
레거시 CSS와 클로드 코드 생성 컴포넌트 격리하기
기존 스타일시트가 거대하게 자리 잡은 프로젝트에 클로드 코드를 투입하면 클래스명이 충돌하면서 화면이 터집니다. 테일윈드 v4의 prefix() 지시어와 CSS Cascade Layers(@layer)로 영역을 확실히 갈라야 합니다.
/* src/styles/globals.css */
@layer legacy, tailwind, overrides;
@layer legacy {
@import "./legacy/old-style.css";
}
@layer tailwind {
@import "tailwindcss" prefix(tw);
}
prefix(tw)를 붙이면 새로 생성되는 클래스는 tw:bg-brand-primary, tw:flex처럼 접두어가 고정됩니다. 기존 레거시 코드의 .btn이나 .card 같은 클래스와 이름이 overlapping될 일이 없어집니다.
폴더 구조도 정리해서 클로드 코드가 건드릴 수 있는 구역을 제한해야 합니다.
- 기존 레거시 코드는
src/legacy/폴더로 치워두고 수정 금지 구역으로 지정합니다. - 클로드 코드가 만들 신규 컴포넌트는
src/design-system/components/에 모읍니다. CLAUDE.md에 접근 제한 규칙을 덧붙입니다.
## Directory Rules
- NEVER edit files inside src/legacy/.
- All NEW frontend components MUST be placed inside src/design-system/components/.
- When creating components, import CSS tokens ONLY from @/design-system/tokens/tokens.css.
단계별 핵심 요약
| 단계 | 적용 내용 | 주요 파일 및 명령 | 기대 효과 |
|---|---|---|---|
| 1. 토큰 선언 | Tailwind v4 @theme 기반 CSS 변수 정의 |
src/styles/globals.css |
AI와 개발자가 공유하는 표준 토큰 기준점 확보 |
| 2. 컨텍스트 설정 | CLAUDE.md 제약 조건 및 공식 스킬 설치 |
claude plugin install frontend-design@claude-plugins-official |
기본 폰트 및 지정되지 않은 그라데이션 남발 차단 |
| 3. 정적 검증 | Oxlint 검증 및 Husky Hook 구성 | npx oxlint --config .oxlintrc.json |
하드코딩 스타일 검출 시 AI가 스스로 코드 수정 |
| 4. 스타일 격리 | Tailwind v4 prefix() 및 @layer 적용 |
@import "tailwindcss" prefix(tw); |
기존 레거시 CSS와의 클래스명 충돌 방지 |
AI가 만드는 코드의 품질은 내보내는 프롬프트보다 받아치는 검증 파이프라인의 견고함에 달려 있습니다. CLAUDE.md에 명확한 금지선을 긋고, Oxlint 기반 검증 스크립트로 하드코딩을 튕겨내면 일일이 스타일을 손보느라 빼앗기던 시간을 되찾을 수 있습니다.
