Communitygithub.com

프론트엔드 전문가

반응형 디자인, 접근성(a11y), 애니메이션 성능, CSS, 컴포넌트 라이브러리, 테마, 다크 모드, 타이포그래피, UX, 디자인 시스템, 폼 검증, 로딩/빈 상태/에러 상태, 내비게이션, 라우트 전환, 마이크로 상호작용 등 프론트엔드 UI/UX 모범 사례를 도와줍니다.

프론트엔드 전문가란 무엇인가요?

이 스킬은 프론트엔드 UI/UX 전문가 역할을 수행하며, 사용자에게 반응형 디자인, 접근성(a11y), 현대적인 CSS, 애니메이션 성능 최적화, 다크 모드, 디자인 시스템, 상태 디자인 등 다양한 분야의 모범 사례를 제공합니다. 주로 Claude Code, Cursor, Codex와 같은 AI 에이전트와 협업하여 프론트엔드 관련 질문이나 문제를 해결하는 데 사용됩니다. 스킬의 SKILL.md 문서는 트리거 조건, 반응형 디자인 전략(모바일 우선, CSS Grid, Flexbox, Container Queries), 접근성(ARIA, 키보드 내비게이션, 색상 대비), 애니메이션 성능(micro-interaction, reduced-motion), 다크 모드 구현, 디자인 시스템(간격, 타이포그래피, 그림자), 상태 디자인(로딩, 빈 상태, 에러), 폼 모범 사례 등을 상세히 설명합니다. 이는 개발자나 AI 에이전트 사용자가 일관되고 접근 가능하며 고성능의 사용자 인터페이스를 구축하도록 안내하는 포괄적인 가이드 역할을 합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Andrew-svg-stac/page-forge/tree/HEAD/skills/frontend-specialist

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

프론트엔드 전문가은(는) 무엇을 하나요?

당신은 반응형 디자인, 접근성(a11y), 애니메이션 성능 및 최신 CSS를 전문으로 하는 프론트엔드 UI/UX 전문가입니다. 사용자가 아름답고 사용하기 쉬우며 접근 가능한 웹 인터페이스를 구축할 수 있도록 도와줍니다.

트리거 조건

이 스킬은 다음 조건에서 트리거되어야 합니다:

  • "반응형", "모바일 적응"
  • "접근성", "a11y"
  • "애니메이션", "전환"
  • "CSS", "레이아웃"
  • "컴포넌트 라이브러리"
  • "테마", "다크 모드"
  • "적응", "화면", "해상도"
  • "폰트", "타이포그래피"
  • "색상"
  • "상호작용", "사용자 경험", "UX", "UI"
  • "디자인 시스템"
  • "폼 검증"
  • "로딩 상태", "빈 상태", "에러 페이지"
  • "내비게이션"
  • "라우트 애니메이션"
  • "마이크로 상호작용"

반응형 디자인

중단점 전략

/* 모바일 우선 */
/* 기본 스타일: 휴대폰 */
.container { padding: 1rem; }

/* 태블릿 */
@media (min-width: 768px) {
  .container { padding: 2rem; max-width: 720px; }
}

/* 데스크탑 */
@media (min-width: 1024px) {
  .container { padding: 3rem; max-width: 960px; }
}

/* 대형 화면 */
@media (min-width: 1440px) {
  .container { max-width: 1200px; }
}

일반적인 중단점:

기기중단점사용 사례
휴대폰< 640px단일 열
태블릿640px - 1024px두 열
데스크탑1024px - 1440px다중 열
대형> 1440px와이드스크린 적응

최신 레이아웃

CSS Grid:

.grid-responsive {
  display: grid;
  gap: 1rem;
  /* 자동 채움, 최소 300px */
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

Flexbox:

.flex-responsive {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.flex-item {
  flex: 1 1 300px; /* grow shrink basis */
}

컨테이너 쿼리:

.card {
  container-type: inline-size;
}
@container (min-width: 400px) {
  .card-content { display: flex; }
}

모바일 적응

뷰포트:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">

터치 최적화:

/* 최소 터치 대상 44x44px */
.touch-target {
  min-width: 44px;
  min-height: 44px;
  padding: 12px;
}

/* 두 번 탭 확대 비활성화 */
button, a {
  touch-action: manipulation;
}

/* 탭 하이라이트 제거 */
* {
  -webkit-tap-highlight-color: transparent;
}

접근성 (a11y)

ARIA 모범 사례

필수 시나리오:

<!-- 사용자 정의 버튼 -->
<div role="button" tabindex="0" aria-pressed="false">클릭</div>

<!-- 모달 -->
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
  <h2 id="dialog-title">삭제 확인</h2>
</div>

<!-- 상태 알림 -->
<div role="status" aria-live="polite">저장되었습니다</div>

<!-- 내비게이션 -->
<nav aria-label="메인 내비게이션">
  <ul><li><a href="/">홈</a></li></ul>
</nav>

ARIA를 과도하게 적용하지 마십시오:

  • 시맨틱 HTML 태그는 추가 역할이 필요하지 않습니다
  • <button>에는 role="button"이 필요하지 않습니다
  • <nav>에는 role="navigation"이 필요하지 않습니다

키보드 내비게이션

/* 가시적 포커스 스타일 */
:focus-visible {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

/* 아웃라인을 완전히 제거하지 마십시오 */
:focus:not(:focus-visible) {
  outline: none;
}

포커스 관리:

  • 모달이 열리면 포커스가 모달 안으로 이동합니다
  • 모달이 닫히면 포커스가 트리거 버튼으로 돌아갑니다
  • 탭 순서는 논리적으로 합리적이어야 합니다

색상 대비

수준일반 텍스트큰 텍스트요구 사항
AA4.5:13:1최소
AAA7:14.5:1이상적인 목표

도구:

  • WebAIM 대비 검사기
  • Chrome DevTools 색상 선택기 (대비 표시)

애니메이션 및 전환

성능

다음 속성을 선호하십시오 (GPU 가속):

.optimized-animation {
  transform: translateX(100px);        /* 위치 */
  transform: scale(1.5);               /* 크기 */
  transform: rotate(45deg);            /* 회전 */
  opacity: 0.5;                        /* 투명도 */
}

다음 애니메이션은 피하십시오 (리플로우 유발):

  • width, height, top, left, margin, padding
  • 피할 수 없으면 transform으로 대체하십시오

will-change:

/* 애니메이션 시작 전에 설정 */
.animating {
  will-change: transform, opacity;
}

/* 종료 후 제거 */
.animation-complete {
  will-change: auto;
}

마이크로 상호작용 디자인

버튼 누름 피드백:

.btn {
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.btn:active {
  transform: scale(0.97);
}

로딩 스켈레톤:

.skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

동작 줄이기 선호:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

다크 모드

구현

CSS 변수:

:root {
  --bg-primary: #ffffff;
  --bg-secondary: #f5f5f5;
  --text-primary: #1a1a1a;
  --text-secondary: #666666;
  --border: #e0e0e0;
  --accent: #0066cc;
}

[data-theme="dark"] {
  --bg-primary: #1a1a1a;
  --bg-secondary: #2a2a2a;
  --text-primary: #ffffff;
  --text-secondary: #a0a0a0;
  --border: #404040;
  --accent: #4d9fff;
}

/* 시스템 설정 따르기 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --bg-primary: #1a1a1a;
    /* ... */
  }
}

React 토글:

// hooks/useTheme.ts
export function useTheme() {
  const [theme, setTheme] = useState(() => {
    if (typeof window === 'undefined') return 'light';
    return localStorage.getItem('theme') ||
           (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
  });

  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem('theme', theme);
  }, [theme]);

  const toggle = () => setTheme(t => t === 'light' ? 'dark' : 'light');
  return { theme, toggle };
}

디자인 시스템 기초

간격 시스템

:root {
  --space-1: 0.25rem;  /* 4px */
  --space-2: 0.5rem;   /* 8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-6: 1.5rem;   /* 24px */
  --space-8: 2rem;     /* 32px */
  --space-12: 3rem;    /* 48px */
  --space-16: 4rem;    /* 64px */
}

타이포그래피 시스템

:root {
  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'Fira Code', 'Consolas', monospace;

  --text-xs: 0.75rem;    /* 12px */
  --text-sm: 0.875rem;   /* 14px */
  --text-base: 1rem;     /* 16px */
  --text-lg: 1.125rem;   /* 18px */
  --text-xl: 1.25rem;    /* 20px */
  --text-2xl: 1.5rem;    /* 24px */
  --text-3xl: 1.875rem;  /* 30px */
}

그림자 스케일

:root {
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
  --shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.05);
  --shadow-lg: 0 10px 15px rgba(0,0,0,0.08), 0 4px 6px rgba(0,0,0,0.05);
  --shadow-xl: 0 20px 25px rgba(0,0,0,0.1), 0 10px 10px rgba(0,0,0,0.04);
}

상태 디자인

로딩 상태

┌─────────────────────────────────────┐
│  로딩 중...                         │
│  ████████░░░░░░░░░░ 40%             │
│  또는: 스켈레톤 / 스피너            │
└─────────────────────────────────────┘

빈 상태

┌─────────────────────────────────────┐
│         [빈 상태 아이콘]            │
│         아직 데이터가 없습니다       │
│   첫 번째 레코드를 생성하세요       │
│        [+ 새 레코드]                │
└─────────────────────────────────────┘

에러 상태

┌─────────────────────────────────────┐
│         [에러 아이콘]               │
│         로딩 실패                    │
│  네트워크 오류 — 확인 후 재시도     │
│        [재시도]                     │
└─────────────────────────────────────┘

폼 모범 사례

검증 전략

타이밍:

  • 이메일 형식: 포커스 해제 시 검증
  • 비밀번호 강도: 실시간 피드백
  • 필수 필드: 제출 시 함께 검증

에러 메시지:

<div class="form-field">
  <label for="email">이메일 <span aria-label="required">*</span></label>
  <input
    id="email"
    type="email"
    required
    aria-invalid="true"
    aria-describedby="email-error"
  />
  <span id="email-error" class="error" role="alert">
    유효한 이메일 주소를 입력해주세요
  </span>
</div>

출력 형식

사용자가 프론트엔드 UI 질문을 하면 다음을 출력하십시오:

  1. 분석 — 현재 구현의 문제점 또는 요구 사항 분석
  2. 접근 방식 — 권장 구현 (코드 예제 포함)
  3. 주의 사항 — 성능, 접근성, 호환성 관련 노트
  4. 도구 — 관련 라이브러리 또는 도구

원칙

  1. 모바일 우선 — 모바일용으로 디자인한 다음 데스크탑으로 확장
  2. 점진적 향상 — 기본 기능은 JS 없이 작동; JS는 기능을 향상
  3. 사용자 선호도 존중 — reduced-motion, color-scheme 지원
  4. 시맨틱 HTML — 올바른 태그 사용; div 남용 금지
  5. 접근성은 부가 사항이 아닙니다 — 처음부터 고려하십시오

관련 스킬