🧪 테스트 가이드
- 키보드: Tab으로 이동하며 포커스 표시와 이동 순서를 비교하세요.
- 스크린 리더: macOS Cmd+F5(VoiceOver) 또는 NVDA를 켜고 각 필드에서 읽히는 내용을 비교하세요.
- 에러 유발: 아무것도 입력하지 않고 제출 버튼을 눌러 에러 처리 방식을 비교하세요.
❌ 접근성 없는 폼
placeholder 라벨 · 에러 시각만 · outline:none
✅ 접근성 있는 폼
label·aria-required·fieldset·aria-invalid·role=alert
표시 항목은 필수입니다.
✅ 회원가입 완료!
주요 차이점
| 항목 | ❌ 접근성 없는 폼 | ✅ 접근성 있는 폼 |
|---|---|---|
| 라벨 | placeholder만 사용 | <label for> 명시 연결 |
| 필수 표시 | 없음 | aria-required + 숨김 텍스트 |
| 입력 힌트 | 없음 | aria-describedby 연결 |
| 에러 처리 | 빨간 테두리만 | aria-invalid + role="alert" |
| 그룹화 | <div> 묶음 | <fieldset> + <legend> |
| 포커스 표시 | outline: none | 명확한 포커스 링 |
❌ 스크린 리더가 에러를 모름
시각적 변화만 — aria 없음
이메일
스크린 리더 발표 로그
버튼을 눌러보세요
✅ 스크린 리더가 즉시 안내
role="alert" + aria-invalid
예: hello@example.com
스크린 리더 발표 로그 (시뮬레이션)
버튼을 눌러보세요
라벨 연결 WCAG 1.3.13.3.2
<!-- ❌ placeholder만 사용 -->
<input type="text" placeholder="이름">
<!-- ✅ label + for/id 연결 -->
<label for="name">
이름 <span aria-hidden="true">*</span>
<span class="sr-only">(필수)</span>
</label>
<input type="text" id="name" required aria-required="true">
에러 처리 WCAG 3.3.13.3.3
<!-- ❌ 시각적 표시만 -->
<input class="has-error" type="email">
<div style="color:red">이메일 형식 오류</div>
<!-- ✅ aria-invalid + role="alert" -->
<input type="email"
aria-invalid="true"
aria-describedby="email-err">
<p id="email-err" role="alert">
올바른 이메일 형식으로 입력해주세요. 예: hello@example.com
</p>
그룹화 WCAG 1.3.1
<!-- ❌ div 묶음 -->
<div>결제 수단</div>
<input type="radio" name="pay"><label>신용카드</label>
<input type="radio" name="pay"><label>계좌이체</label>
<!-- ✅ fieldset + legend (읽힘: "결제 수단, 신용카드, 라디오 1/2") -->
<fieldset>
<legend>결제 수단 <span class="sr-only">(필수)</span></legend>
<label><input type="radio" name="pay" value="card"> 신용카드</label>
<label><input type="radio" name="pay" value="wire"> 계좌이체</label>
</fieldset>
포커스 스타일 WCAG 2.4.72.4.11
/* ❌ 절대 하지 마세요 */
input:focus { outline: none; }
/* ✅ 명확한 포커스 링 */
input:focus {
outline: 2px solid #5558e3;
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(85,88,227,.25);
}