웹 접근성 기초 가이드
모든 사용자가 이용할 수 있는 웹을 만드는 방법. 웹 접근성의 기본 원칙과 실전 적용법을 알아봅니다.
웹 접근성은 장애가 있는 사람도 웹을 이용할 수 있게 하는 것입니다. 시각, 청각, 운동 장애뿐만 아니라 일시적인 상황(밝은 햇빛, 한 손 사용)도 포함됩니다.
접근성이 중요한 이유
세계 인구의 약 15%가 어떤 형태로든 장애를 가지고 있습니다. 접근성을 고려하지 않으면 이 사용자들을 배제하는 것입니다.
또한 접근성은 모든 사용자의 경험을 향상시킵니다. 키보드 내비게이션, 명확한 구조, 충분한 대비는 모두에게 도움이 됩니다.
SEO에도 긍정적입니다. 검색 엔진은 시각 장애인용 스크린 리더와 비슷한 방식으로 웹페이지를 읽습니다.
시맨틱 HTML
HTML 요소를 의미에 맞게 사용합니다.
<!-- 나쁜 예 -->
<div class="header">
<div class="nav">
<span onclick="goHome()">홈</span>
</div>
</div>
<div class="main-content">
<div class="article">
<span class="title">제목</span>
</div>
</div>
<!-- 좋은 예 -->
<header>
<nav>
<a href="/">홈</a>
</nav>
</header>
<main>
<article>
<h1>제목</h1>
</article>
</main>
시맨틱 태그는 스크린 리더가 페이지 구조를 이해하는 데 도움을 줍니다.
키보드 접근성
마우스 없이 키보드만으로 모든 기능을 사용할 수 있어야 합니다.
포커스 가능한 요소
<!-- 기본적으로 포커스 가능 -->
<a href="...">링크</a>
<button>버튼</button>
<input type="text" />
<!-- 포커스 불가능을 가능하게 -->
<div tabindex="0" role="button" onclick="...">
커스텀 버튼
</div>
포커스 표시
포커스된 요소가 시각적으로 구분되어야 합니다.
/* 기본 포커스 스타일을 제거하지 마세요 */
button:focus {
outline: none; /* 이렇게 하지 마세요 */
}
/* 대신 더 좋은 스타일로 대체하세요 */
button:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
/* 또는 focus-visible 사용 */
button:focus-visible {
outline: 2px solid #0066cc;
}
이미지 대체 텍스트
모든 이미지에는 대체 텍스트가 필요합니다.
<!-- 의미 있는 이미지 -->
<img src="chart.png" alt="2025년 매출 그래프: 1분기 100억, 2분기 150억" />
<!-- 장식용 이미지 -->
<img src="decoration.png" alt="" role="presentation" />
<!-- 텍스트가 포함된 이미지 -->
<img src="logo.png" alt="회사명" />
alt 텍스트는 이미지의 내용이나 목적을 설명해야 합니다. "이미지" 또는 "사진"이라고 쓰지 않습니다.
색상 대비
텍스트와 배경의 대비가 충분해야 합니다. WCAG 기준으로 일반 텍스트는 4.5:1, 큰 텍스트는 3:1 이상이어야 합니다.
/* 대비가 부족한 예 */
.low-contrast {
color: #999999;
background: #ffffff;
/* 대비 2.85:1 - 부족 */
}
/* 충분한 대비 */
.good-contrast {
color: #595959;
background: #ffffff;
/* 대비 7:1 - 충분 */
}
색상만으로 정보를 전달하지 않습니다. 에러 메시지는 빨간색과 함께 아이콘이나 텍스트로도 표시합니다.
폼 접근성
<!-- 라벨 연결 -->
<label for="email">이메일</label>
<input type="email" id="email" name="email" />
<!-- 또는 라벨로 감싸기 -->
<label>
이메일
<input type="email" name="email" />
</label>
<!-- 에러 메시지 연결 -->
<label for="password">비밀번호</label>
<input
type="password"
id="password"
aria-describedby="password-error"
aria-invalid="true"
/>
<p id="password-error" class="error">
비밀번호는 8자 이상이어야 합니다.
</p>
필수 입력 표시
<label for="name">
이름 <span aria-hidden="true">*</span>
<span class="sr-only">(필수)</span>
</label>
<input type="text" id="name" required aria-required="true" />
ARIA 속성
HTML만으로 부족할 때 ARIA 속성을 사용합니다.
<!-- 토글 버튼 -->
<button aria-pressed="false" onclick="toggle()">
알림 켜기
</button>
<!-- 모달 -->
<div role="dialog" aria-modal="true" aria-labelledby="modal-title">
<h2 id="modal-title">확인</h2>
<p>정말 삭제하시겠습니까?</p>
</div>
<!-- 로딩 상태 -->
<div aria-busy="true" aria-live="polite">
로딩 중...
</div>
<!-- 탭 UI -->
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel-1">탭 1</button>
<button role="tab" aria-selected="false" aria-controls="panel-2">탭 2</button>
</div>
<div role="tabpanel" id="panel-1">탭 1 내용</div>
<div role="tabpanel" id="panel-2" hidden>탭 2 내용</div>
주의사항
ARIA는 HTML의 기본 접근성을 보완하는 것입니다. 가능하면 시맨틱 HTML을 먼저 사용하세요.
<!-- 불필요한 ARIA -->
<button role="button">클릭</button>
<!-- button은 이미 role="button" -->
<button>클릭</button>
테스트 도구
자동화 도구
- Lighthouse (Chrome DevTools)
- axe DevTools (브라우저 확장)
- eslint-plugin-jsx-a11y (React)
수동 테스트
- 키보드만으로 사용해보기
- 스크린 리더로 테스트 (VoiceOver, NVDA)
- 색상 대비 체커 사용
마무리
완벽한 접근성은 어렵지만, 기본적인 것만 지켜도 많은 사용자에게 도움이 됩니다.
시맨틱 HTML 사용, 키보드 접근성 확보, 충분한 색상 대비. 이 세 가지부터 시작하세요.