Files
game-fe-agent/skills/verify-a11y/SKILL.md

131 lines
4.0 KiB
Markdown

---
name: verify-a11y
description: |
Vue 3 / HTML 코드를 WCAG 2.1 AA 기준으로 자동 감사하고
ARIA 레이블 누락, 키보드 포커스 순서, 색상 대비 비율 등의 문제와
코드 레벨 개선 방안을 제시합니다.
다음 상황에서 반드시 사용하세요:
- "접근성 검증해줘", "WCAG 체크해줘", "a11y 확인해줘"
- ARIA 속성이 빠진 것 같을 때
- QA 전 접근성 관련 반려를 사전에 방지하고 싶을 때
---
# 접근성 검증 (verify-a11y)
Vue 3 / HTML → WCAG 2.1 AA 자동 감사 → 코드 레벨 개선 방안 리포트.
## 언제 사용하는가
- 마크업 완료 후 접근성 기준 충족 여부를 확인할 때
- 스크린 리더 사용자를 위한 ARIA 적용이 필요할 때
- 키보드 전용 사용자 지원이 필요할 때
## 검사 기준: WCAG 2.1 AA
| 원칙 | 핵심 항목 |
|---|---|
| **인식 가능** | 이미지 대체 텍스트, 색상 대비 비율, 캡션 |
| **운용 가능** | 키보드 접근성, 포커스 순서, 충분한 시간 |
| **이해 가능** | 레이블, 오류 식별, 일관된 네비게이션 |
| **견고성** | 유효한 HTML, ARIA 역할 |
---
## 작업 순서
### Phase 1: 코드 수집
1. 검증 대상 파일을 읽는다. (`.vue`, `.html`, 템플릿 코드)
2. 검증 범위가 넓으면 화면 단위로 분리해 진행한다.
### Phase 2: 체크리스트 점검
#### 이미지 & 미디어
- [ ] 의미 있는 `<img>`: `alt` 텍스트 존재
- [ ] 장식용 `<img>`: `alt=""`
- [ ] `<video>`: 자막(captions) 또는 스크립트 제공
#### 색상 대비
- [ ] 일반 텍스트: 대비 비율 4.5:1 이상
- [ ] 대형 텍스트 (18px+ 또는 14px+ bold): 3:1 이상
- [ ] 아이콘/그래픽 UI: 3:1 이상
#### 키보드 접근성
- [ ] 모든 인터랙션 요소가 키보드로 접근 가능
- [ ] 포커스 순서가 시각적 레이아웃과 일치
- [ ] 포커스 링(outline) 가시성 확보 (`:focus-visible`)
- [ ] 모달/드롭다운 열릴 때 포커스 이동, 닫힐 때 원래 요소로 복귀
#### ARIA 적용
- [ ] `<button>` 아이콘 전용: `aria-label` 또는 `aria-labelledby`
- [ ] 모달: `role="dialog"`, `aria-modal="true"`, `aria-labelledby`
- [ ] 폼 에러: `aria-describedby` → 에러 메시지 연결
- [ ] 로딩 영역: `aria-live="polite"` 또는 `aria-busy="true"`
- [ ] 탭 UI: `role="tablist"`, `role="tab"`, `role="tabpanel"`, `aria-selected`
- [ ] 아코디언: `aria-expanded`, `aria-controls`
- [ ] 드롭다운 메뉴: `aria-haspopup`, `aria-expanded`
#### 폼
- [ ] 모든 입력 필드에 연결된 `<label>` 존재
- [ ] 필수 필드: `aria-required="true"` 또는 `required`
- [ ] 에러 메시지: `role="alert"` 또는 `aria-live="assertive"`
#### 제목 계층
- [ ] `h1``h2``h3` 순서 준수 (건너뛰기 없음)
- [ ] 페이지에 `h1` 1개만 존재
#### 랜드마크
- [ ] `<header>`, `<nav>`, `<main>`, `<footer>` 적절히 사용
- [ ] 여러 `<nav>`가 있으면 `aria-label`로 구분
### Phase 3: 개선 방안 코드 제시
```vue
<!-- Before: 아이콘 버튼 접근성 없음 -->
<button @click="close">
<IconClose />
</button>
<!-- After: aria-label 추가 -->
<button @click="close" aria-label="닫기">
<IconClose aria-hidden="true" />
</button>
```
```vue
<!-- Before: 에러 접근성 없음 -->
<input type="email" />
<p class="text-red-500">올바른 이메일을 입력하세요</p>
<!-- After -->
<input
type="email"
:aria-describedby="hasError ? 'email-error' : undefined"
:aria-invalid="hasError"
/>
<p v-if="hasError" id="email-error" role="alert">
올바른 이메일을 입력하세요
</p>
```
---
## 출력 형식
```
## 접근성 검증 리포트: <파일명>
### 🚨 Critical — WCAG 위반 (N건)
- [라인 NN] 문제 설명 + 수정 코드
### ⚠️ Warning — 개선 권장 (N건)
- [라인 NN] 문제 설명 + 수정 방향
### 💡 Info — 선택 개선 (N건)
- [라인 NN] 개선 사항
### ✅ 적절히 처리된 항목
- ARIA 레이블 적용됨, 색상 대비 충족 등
```