← 홈페이지 5강 목록으로
📋
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; }
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗