Communitygithub.com

프론트엔드 품질 (Frontend Quality)

React/Next.js/Astro/Svelte/Vue 등 프론트엔드 프로젝트에서 접근성(WCAG 2.2 AA), 성능(Core Web Vitals: LCP/INP/CLS), 시맨틱 HTML, 이미지 최적화, 번들 크기, 모바일 우선, 로딩/빈/에러 상태 등 사용자 중심 품질 기준을 강제합니다. [Project A] (아르헨티나 모바일 사용자, 느린 3G/4G)와 [회사] 문서 사이트(빠른 성능을 기대하는 개발자)에 필수적입니다. `*.tsx`, `*.jsx`, `*.svelte`, `*.vue`, `*.astro`, `*.css` 파일 변경 시 자동 트리거됩니다.

프론트엔드 품질 (Frontend Quality)란 무엇인가요?

이 스킬은 프론트엔드 개발자가 PR에서 놓치기 쉬운 사용자 경험 버그(느린 페이지, 깨진 키보드 탐색, 로딩 중 레이아웃 변경)를 체계적으로 검토합니다. WCAG 2.2 AA 접근성(키보드, 시맨틱 HTML, 색상 대비, 폼, 이미지)과 Core Web Vitals(LCP <2.5s, INP <200ms, CLS <0.1)를 하드 요구사항으로 적용하고, 다섯 가지 UI 상태(로딩, 빈, 에러, 부분/오래된, 성공) 누락을 차단합니다. Next.js, Astro, Svelte, Vue 등 주요 프레임워크를 지원하며, 모델 라우팅을 통해 운영자가 선호하는 LLM(기본 Claude)으로 리뷰를 수행합니다. 개발자는 CI에서 Lighthouse, axe-core, bundlewatch 등을 통합하여 품질을 자동 검증할 수 있습니다. 하드 룰(예: `<div onClick>` 금지, `alt` 속성 필수)은 절대 예외 없이 적용되며, 출력은 [차단/경고/제안] 형식으로 문제 위치, 범주, 영향, 수정 방법, 검증 방법을 명시합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Xipher-Labs/walter-os/tree/HEAD/skills/frontend-quality

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

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

문서

프론트엔드 품질

사용자 대면 웹 UI에 대한 품질 기준입니다. 하드 요구사항(접근성, 성능, 모바일 우선)이며 스타일 선호도가 아닙니다. 리뷰는 실제 사용자에게 영향을 미치는 버그(느린 페이지, 깨진 키보드 탐색, 로딩 중 레이아웃 변경)를 잡아냅니다.

모델 라우팅

모델이 UI, UX, 시각적 계층, 접근성 카피 또는 상호작용 세부사항을 비판하거나 재작성해야 할 때 운영자의 프론트엔드 선호도를 사용하세요:

source "$WALTER_OS_HOME/scripts/walter/lib/model-router.sh"
frontend_model=""
walter_model_resolve frontend frontend_model

기본 선호도는 Claude입니다. 운영자는 ~/.config/walter-os/overlay/personal.env에서 별칭을 다른 LiteLLM 경로로 지정할 수 있습니다.

이 스킬은 프론트엔드 변경 diff에 자동 트리거됩니다. 처음부터 랜딩 페이지를 구축하려면 landing-page-fast(이 규칙을 포함하지만 스캐폴딩도 제공)를 사용하세요.

이 운영자에게 특히 중요한 이유

  • [Project A] 사용자는 아르헨티나 SMB 공급업체로, 대부분 휴대폰을 사용하며 종종 3G/4G 연결이 불안정합니다. 느린 사이트 = 사용자 이탈. WCAG가 중요한 이유는 일부 사용자가 기술 문맹률이 낮고 시력이 손상되었기 때문입니다.
  • [Project B] 사용자는 장애가 있는 환자를 포함합니다. WCAG는 '있으면 좋은 것'이 아니라 사용성 요구사항입니다.
  • [회사] 문서는 정교한 개발자가 읽으며 느리거나 키보드가 깨진 사이트에서 즉시 이탈합니다.

접근성 (WCAG 2.2 AA — 필수)

키보드

  • 모든 상호작용 요소가 Tab으로 접근 가능해야 합니다. 버튼, 링크, 양식 필드, 사용자 정의 컨트롤. 수동 Tab-through를 실행하세요. 컨트롤이 하나라도 건너뛰어지면 차단(BLOCKER)입니다.
  • 포커스가 보여야 합니다. :focus-visible 아웃라인이 명확해야 합니다. 대체 없이 outline: none을 설정하지 마세요.
  • 논리적인 탭 순서. 읽기 순서가 DOM 순서와 일치해야 하며, tabindex 값이 0보다 큰 것은 피하세요(자연스러운 흐름을 깨뜨립니다).
  • 건너뛰기 링크. 모든 페이지의 첫 번째 포커스 가능 요소는 '주요 콘텐츠로 건너뛰기'여야 합니다.
  • Escape 키로 모달 닫기. 모달이 닫힐 때까지 포커스를 모달 내에 가둡니다.

시맨틱 HTML

  • <button>은 액션용, <a>는 탐색용입니다. 둘 다 <div onClick>을 사용하지 마세요.
  • 제목 계층 구조: 페이지당 하나의 <h1>; <h2> ... <h6>는 단계를 건너뛰지 않습니다.
  • 랜드마크: <header>, <nav>, <main>, <footer>. ARIA 역할은 어울리는 시맨틱 요소가 없을 때만 사용합니다.
  • **목록은 <ul>/<ol>**입니다. <div>로 목록을 위조하지 마세요.
  • **양식 컨트롤에는 <label>**이 있어야 합니다. for 속성이 id와 일치해야 합니다.

색상 및 대비

  • WCAG AA 최소 대비: 본문 텍스트 4.5:1, 큰 텍스트(18pt+ 또는 14pt+ 볼드) 3:1, UI 구성 요소 및 그래픽 3:1.
  • 색상이 유일한 지표가 아님: 오류 상태는 빨간색 테두리뿐만 아니라 아이콘 + 텍스트 + 색상을 표시합니다.
  • 색맹 시뮬레이션으로 테스트됨. Stark, axe DevTools 또는 브라우저 개발자 도구 색각 시뮬레이터를 사용하세요.

양식

  • 모든 입력에는 눈에 보이는 레이블이 있습니다. 플레이스홀더는 레이블이 아닙니다.
  • 오류 메시지는 aria-describedby를 통해 프로그래밍 방식으로 연결됩니다.
  • 필수 필드 표시. 시각적으로(* 또는 '필수') AND 프로그래밍 방식으로(aria-required="true" 또는 required) 모두 표시합니다.
  • 유효성 검사 오류는 포커스를 받아도 사라지지 않습니다. 수정되거나 해제될 때까지 유지됩니다.
  • 성공 상태 확인. 제출 후 스크린 리더 사용자가 성공했음을 알 수 있어야 합니다.

이미지 및 미디어

  • 모든 <img>에 alt 속성. 장식용은 빈 값(alt=""), 콘텐츠용은 설명적. 생성형 AI 이미지: 프롬프트가 아니라 이미지에 실제로 있는 내용을 설명하세요.
  • 비디오/오디오용 자막/대본.
  • 소리와 함께 자동 재생 금지.
  • 애니메이션이 prefers-reduced-motion을 존중합니다:
    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
      }
    }
    

도구

  • 개발 모드에서 @axe-core/react — 접근성 문제를 콘솔에 기록합니다.
  • eslint-plugin-jsx-a11y — 빌드 시점에 잡아냅니다.
  • 출시 전 수동 스크린 리더 테스트: VoiceOver (Mac), NVDA (Windows), TalkBack (Android).
  • CI에서 Lighthouse 접근성 점수 ≥ 95.

성능 — Core Web Vitals

Google이 순위를 매기는 3가지 지표입니다. 'Good'으로 평가받으려면 세 가지 모두 통과해야 합니다:

LCP (Largest Contentful Paint) — 로드 속도

목표: 3G에서 < 2.5초. [Project A]의 실제 환경은 아르헨티나 모바일 네트워크가 중간보다 느리므로 더 공격적입니다.

방법:

  • LCP 이미지 사전 로드: <link rel="preload" as="image" href="...">.
  • 렌더링 차단 리소스 없음: 중요하지 않은 JS는 지연, 중요 CSS는 인라인.
  • 폰트 자체 호스팅 font-display: swap과 함께 또는 시스템 폰트 스택 사용.
  • 정적 자산용 CDN: Vercel, Cloudflare R2, Bunny.net.
  • HTTP/2 또는 HTTP/3: Vercel/Cloudflare 기본값.
  • 이미지 압축: WebP/AVIF, 뷰포트에 맞게 크기 조정.
  • 히어로 이미지 특별 최적화: 거의 항상 LCP입니다.

INP (Interaction to Next Paint) — 응답성

목표: p75 < 200ms. 2024년 FID를 대체했습니다.

방법:

  • 상호작용 중 메인 스레드에 50ms 이상의 긴 작업 없음.
  • 하이드레이션 지연 (Astro islands, Next.js streaming, qwik).
  • 무거운 계산은 Web Worker.
  • 입력 핸들러 디바운스/스로틀.
  • 큰 문자열로 dangerouslySetInnerHTML 사용 금지 — 파싱이 차단됩니다.
  • useMemo/memo는 측정된 경우에만, 선제적으로 사용하지 않음.

CLS (Cumulative Layout Shift) — 시각적 안정성

목표: < 0.1.

방법:

  • 이미지 및 비디오 태그에 width + height (브라우저가 공간을 예약합니다).
  • 광고/임베드용 공간 예약 min-height로.
  • 기존 콘텐츠 위에 콘텐츠를 삽입하지 않음: 알림 배너는 접힌 부분 아래에 배치하거나 transform으로 밀어내되 DOM 위에 삽입하지 않음.
  • 웹 폰트: font-display: swap + size-adjust를 사용하여 메트릭 일치, 또는 가능한 경우 font-display: optional.
  • 스켈레톤 스크린 실제 콘텐츠와 일치하는 크기로.

번들 크기

  • 초기 JS 예산: 랜딩 페이지 < 150KB gzipped, 앱 셸 < 250KB.
  • 경로별 코드 분할 (Next.js, Astro, SvelteKit이 기본적으로 수행).
  • 무겁고 중요하지 않은 종속성(차트, 편집기)은 동적 임포트.
  • 종속성 감사: bundle-analyzer 또는 next-bundle-analyzer. 하나의 컴포넌트를 위해 가져온 10MB UI 라이브러리를 버리세요.
  • 트리 쉐이킹 작동: 필요한 것만 가져오기(import { thing } from 'lib' 이지 import lib from 'lib'가 아님).

로딩 패턴

  • 필요한 출처에 미리 연결: <link rel="preconnect" href="...">.
  • 호버/포커스 시 다음 페이지를 미리 가져오기 (Next.js가 수행).
  • 접힌 부분 아래 이미지는 지연 로딩: loading="lazy".
  • iframe 지연 로딩: loading="lazy".
  • 오프라인 우선을 위한 서비스 워커 (적합한 경우 — [Project A]에 유리, 마케팅 페이지는 해당 없음).

상태 — 모든 컴포넌트가 다섯 가지를 모두 처리

데이터 기반 UI의 경우, 상태가 하나라도 처리되지 않으면 차단(BLOCKER)입니다:

  1. 로딩 — 스켈레톤 또는 스피너. 빈 화면이 아니어야 함. 레이아웃 변경이 없어야 함.
  2. 빈 상태 — 첫 번째, 데이터가 없는 상태. 채우기 위한 CTA 포함.
  3. 오류 — 명확한 메시지, 재시도 버튼, 사용자에게 스택 트레이스 없음. Sentry에 기록.
  4. 부분 / 오래된 상태 — 데이터가 캐시 또는 부분 가져오기에서 온 경우.
  5. 성공 — 정상 경로.

목록 예시:

if (isLoading) return <ListSkeleton />
if (error)     return <ErrorState onRetry={refetch} />
if (data.length === 0) return <EmptyState cta={...} />
return <List items={data} />

컴포넌트가 diff에 성공 상태만 표시했다면, 나머지 4개는 어디에 있는지 물어보세요.

모바일 우선

  • 360px 너비를 먼저 디자인하고 확장.
  • 터치 대상 ≥ 44×44px (Apple HIG) 또는 48×48px (Material).
  • hover 전용 상호작용 없음: hover에서 사용 가능한 모든 것은 포커스/터치 경로도 있어야 함.
  • 실제 기기 또는 Chrome DevTools throttled에서 테스트: 3G 네트워크, 4배 CPU 저속.
  • 확대 없이 양식 작동: input font-size: 16px+ (그렇지 않으면 iOS가 포커스 시 확대).

도구 참조

CI / 병합 전:

  • Lighthouse CI 지표별 예산 포함.
  • @axe-core/cli 또는 Lighthouse 접근성 하위 집합.
  • bundlewatch 예산을 초과하는 번들로 PR을 실패 처리.
  • 시각적 회귀: Chromatic (Storybook), Percy 또는 Playwright 스크린샷 검사.

로컬:

  • Chrome DevTools Performance + Lighthouse 패널.
  • unlighthouse 전체 사이트 감사.
  • @unjs/check-vitals 일회성 Web Vitals.

출력 형식

**[차단|경고|제안] [FE-N] <한 줄 설명>**

위치: `path/to/Component.tsx:42-58`
범주: <a11y | perf | states | mobile | semantic>
영향: <어떤 사용자 / 시나리오 / 지표>
수정: <구체적인 변경, 적합하면 코드>
검증: <확인 방법 — Lighthouse 실행 / 수동 테스트 / 등>

심각도:

  • 차단(BLOCKING): WCAG AA 위반, 핵심 흐름 손상, Web Vitals 'Poor' 범위. 반드시 수정.
  • 경고(WARN): 모범 사례 격차, 아직 사용자에게 보이지 않는 성능 회귀.
  • 제안(NIT): 개선 기회 (더 작은 번들, 더 나은 스켈레톤).

하드 룰

  • 버튼에 <div onClick> 사용 금지. 항상.
  • alt 없는 이미지 금지. 항상.
  • 실제 콘텐츠로 인한 레이아웃 변경 금지. 항상 공간을 예약.
  • 소리와 함께 자동 재생 금지. 항상.
  • prefers-reduced-motion 존중. 항상.

이 스킬이 다루지 않는 것

  • 백엔드 (web-security-baseline 사용).
  • DB 스키마 / 쿼리 (data-migration-safety 사용).
  • 브랜드 아이덴티티 / 시각적 디자인 (brand-creation 사용).
  • 새 랜딩 페이지 구축 (landing-page-fast 사용, 스캐폴딩 제공).

참고 자료

  • WCAG 2.2 빠른 참조
  • web.dev Core Web Vitals 문서
  • web.dev Performance 학습 경로
  • Heydon Pickering의 Inclusive Components
  • A11y Project 체크리스트

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

관련 스킬