📋
EPISODE 03
label · 에러 메시지 · 색상 대비 · :focus-visible
폼 접근성
label과 input 연결 3가지 방식, role="alert"와 aria-describedby로 에러 전달, aria-required/aria-invalid, 색상 대비 4.5:1, 그리고 절대 제거하면 안 되는 포커스 스타일.
폼labelcolor contrast
소요 시간
⏱ 45분
난이도
📊 중급
선수 조건
🎯 a11y-02
결과물
스크린리더가 정확히 안내하는 회원가입 폼
이 강의에서 배우는 것
- 1label-for-id, 감싸기, aria-label 3가지 연결 방식을 안다
- 2role="alert"와 aria-describedby로 에러를 전달한다
- 3aria-required / aria-invalid 를 적절히 토글한다
- 4WCAG AA 색상 대비(4.5:1)를 만족한다
- 5:focus-visible로 포커스 스타일을 안전하게 유지한다
1. label과 input 연결
방법 1: for/id (권장)
html
<label for="username">사용자 이름</label>
<input type="text" id="username" name="username">방법 2: 감싸기
html
<label>
사용자 이름
<input type="text" name="username">
</label>방법 3: aria-label
html
<input type="search" aria-label="검색어 입력" placeholder="검색어">⚠️
placeholder는 레이블 대체품이 아닙니다! 입력 시작하면 사라지고 대비도 낮음.
2. 에러 메시지 — role="alert"
html
<!-- 동적 추가 시 스크린리더가 즉시 읽음 -->
<div role="alert">
이메일 형식이 올바르지 않습니다. (예: user@example.com)
</div>
<label for="email">이메일</label>
<input
type="email"
id="email"
aria-describedby="email-error"
aria-invalid="true"
required
>
<p id="email-error" role="alert">
이메일 형식이 올바르지 않습니다.
</p>3. aria-required / aria-invalid
html
<input type="text" required aria-required="true">
<input aria-invalid="false"> <!-- 통과 전 -->
<input aria-invalid="true" aria-describedby="error-msg"> <!-- 에러 -->
<span id="error-msg">필수 입력 항목입니다.</span>
<!-- 여러 도움말 연결 (공백 구분) -->
<input type="password" id="pw" aria-describedby="pw-hint pw-error">
<p id="pw-hint">8자 이상, 대소문자+숫자+특수문자</p>
<p id="pw-error" role="alert" hidden>비밀번호가 조건을 충족하지 않습니다.</p>4. 색상만으로 정보 전달 금지
html
<!-- ✗ 색상만 -->
<input style="border-color: red">
<!-- ✓ 색상 + 아이콘 + 텍스트 -->
<div class="field-error">
<input aria-invalid="true" aria-describedby="email-error">
<span class="error-icon" aria-hidden="true">⚠</span>
<p id="email-error" role="alert">이메일 형식이 올바르지 않습니다.</p>
</div>5. 색상 대비 (Contrast Ratio)
- 일반 텍스트: 최소 4.5:1
- 큰 텍스트(18pt 이상): 최소 3:1
- UI 요소(테두리, 아이콘): 최소 3:1
css
/* ✗ 대비율 2.3:1 */
input { border: 1px solid #cccccc; }
label { color: #aaaaaa; }
/* ✓ 4.5:1 이상 */
input { border: 2px solid #767676; }
label { color: #1a1a1a; }확인: WebAIM Contrast Checker — https://webaim.org/resources/contrastchecker/
6. 포커스 스타일 — 절대 제거 금지!
css
/* ✗ 절대 금지 */
:focus { outline: none; }
/* ✓ 방법 1: 기본 outline 개선 */
:focus-visible {
outline: 3px solid #0066cc;
outline-offset: 2px;
border-radius: 2px;
}
/* ✓ 방법 2: 마우스는 숨기고 키보드만 표시 */
:focus { outline: none; }
:focus-visible { outline: 3px solid #0066cc; }