의미 있는 시멘틱 HTML은 스크린 리더가 콘텐츠를 올바르게 해석하도록 돕고, SEO와 코드 가독성을 개선합니다.
비시멘틱 태그(예: <div>)는 스크린 리더가 버튼, 내비게이션 등의 역할을 인식하지 못합니다. 그래서, <button>, <nav>, <main> 같은 시멘틱 태그를 통해 콘텐츠의 역할과 구조를 명확히 전달해야 합니다.
버튼은 <button>, 링크는 <a>, 내비게이션은 <nav>로 구현.
페이지 구조를 <header>, <main>, <footer>로 정의.
콘텐츠 그룹핑에 <section>, <article> 사용.
예시
<header>
<nav aria-label="주요 내비게이션">
<ul>
<li><a href="/">홈</a></li>
<li><a href="/about">소개</a></li>
</ul>
</nav>
</header>
<main>
<section>
<h1>웹 접근성</h1>
<article>
<p>모든 사용자를 위한 설계</p>
</article>
</section>
</main>
<footer>
<p>© 2025</p>
</footer>
검증 방법
Chrome 개발자 도구의 Accessibility Tree로 시멘틱 구조 확인.
NVDA 또는 VoiceOver로 페이지 탐색 테스트(예: 내비게이션, 제목 순서 확인).
Lighthouse의 Accessibility 점수로 구조적 문제 점검.
ARIA(Accessible Rich Internet Applications)는 동적 콘텐츠와 비표준 UI의 접근성을 개선합니다.
스크린 리더가 복잡한 인터페이스를 이해하도록 역할, 상태, 속성을 명시한다.
SPA(예: React)에서 모달, 알림 등 동적 콘텐츠가 스크린 리더에 전달되지 않을 수 있기에 ARIA는 보조 기술과의 호환성을 높여 접근성을 강화해야 합니다.
적용 방법
role로 요소의 역할 정의(예: alert, dialog, button).
aria-live로 동적 콘텐츠 업데이트 알림(예: polite, assertive).
aria-label, aria-describedby로 추가 설명 제공.
aria-hidden으로 스크린 리더가 무시할 요소 지정.
예시
동적 에러 메시지
<div role="alert" aria-live="assertive">오류: 이메일을 입력하세요</div>
버튼에 설명
<button aria-label="메뉴 열기">☰</button>
입력 필드 설명
<input id="email" type="email" aria-describedby="email-help">
<span id="email-help">유효한 이메일을 입력하세요</span>
<div role="dialog" aria-labelledby="modal-title" aria-modal="true">
<h2 id="modal-title">로그인</h2>
<form>
<label for="username">사용자 이름</label>
<input id="username" type="text">
</form>
<button aria-label="모달 닫기">X</button>
</div>
<!-- 장식용 요소 숨김 -->
<span aria-hidden="true" class="decorative-icon">★</span>
React에서 ARIA 적용
function Modal() {
return (
<div role="dialog" aria-labelledby="modal-title">
<h2 id="modal-title">알림</h2>
<button aria-label="닫기" onClick={closeModal}>X</button>
</div>
);
}
동적 콘텐츠 업데이트
const alert = document.createElement('div');
alert.setAttribute('role', 'alert');
alert.setAttribute('aria-live', 'polite');
alert.textContent = '새 메시지 도착';
document.body.appendChild(alert);
주의점
잘못된 ARIA는 스크린 리더에 혼란을 줄 수 있음.
시멘틱 HTML로 해결 가능한 경우 ARIA 최소화(예: <button>에 role="button" 불필요)
검증 방법
axe DevTools로 ARIA 이슈 진단.
VoiceOver로 ARIA 속성 동작 확인(예: 모달 열림 알림).
NVDA로 aria-live 알림 테스트.
운동장애인이나 마우스를 사용하지 않는 사용자를 위해 모든 인터랙티브 요소(버튼, 링크, 폼 등)가 키보드로 조작 가능해야 합니다.
WCAG는 모든 기능을 키보드로 사용할 수 있어야 한다고 명시.
기본 포커스 가능 요소(<a>, <button>, <input>) 사용.
tabindex로 포커스 순서 관리:
tabindex="0": 자연스러운 포커스 가능.
tabindex="-1": JavaScript로만 포커스 가능.
동적 콘텐츠 추가 시 포커스 이동 관리.
:focus 스타일로 시각적 피드백 제공.
예시
포커스 가능한 링크
<a href="/home" tabindex="0">홈</a>
동적 포커스
<div id="new-content" tabindex="-1">새 콘텐츠</div>
<script>
document.getElementById('new-content').focus();
</script>
포커스 스타일
a:focus, button:focus, [tabindex="0"]:focus {
outline: 2px solid #005FCC;
outline-offset: 2px;
}
드롭다운 메뉴
<div role="menu" tabindex="0" aria-label="옵션 메뉴">
<div role="menuitem" tabindex="-1">옵션 1</div>
<div role="menuitem" tabindex="-1">옵션 2</div>
</div>
<script>
const menu = document.querySelector('[role="menu"]');
menu.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
console.log('메뉴 항목 선택');
}
});
</script>
모달 열릴 때 포커스 이동
function openModal() {
const modal = document.querySelector('[role="dialog"]');
modal.setAttribute('aria-modal', 'true');
modal.querySelector('button').focus();
}
Tab 트랩(Tab Trap)으로 모달 내 포커스 유지
const modal = document.querySelector('[role="dialog"]');
const focusableElements = modal.querySelectorAll('a, button, input');
const first = focusableElements[0];
const last = focusableElements[focusableElements.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
검증 방법
Tab 키로 내비게이션 테스트(논리적 순서 확인).
포커스 스타일이 시각적으로 명확한지 확인.
NVDA로 포커스 이동 및 알림 확인.
낮은 대비는 색맹(예: 적록색맹)이나 저시력 사용자가 텍스트를 인식하지 못하게 해 텍스트와 배경 간 색상 대비를 WCAG 기준(최소 4.5:1)으로 유지해 색맹 및 저시력 사용자가 콘텐츠를 쉽게 읽을 수 있도록 해야합니다.
텍스트와 배경 색상 대비 4.5:1 이상 유지(큰 텍스트는 3:1).
색상만으로 정보 전달 피하기(예: 빨간색으로만 에러 표시 X).
고대비 모드 지원.
예시
적절한 대비
.text {
color: #000000; /* 검정 */
background-color: #FFFFFF; /* 흰색 */
}
고대비 모드
@media (prefers-contrast: high) {
.text {
color: #FFFFFF;
background-color: #000000;
}
}
색상 외 단서
<span style="color: red; border: 1px solid red;" aria-live="polite">오류: 입력 필요</span>
버튼 스타일
button {
background-color: #005FCC;
color: #FFFFFF;
border: 2px solid transparent;
}
button.error {
background-color: #D32F2F;
border-color: #FFFFFF; /* 색상 외 단서 */
}
WebAIM Contrast Checker로 색상 대비 확인.
색맹 시뮬레이터(예: Stark)로 테스트.
CSS 변수로 색상 관리:
:root {
--text-color: #000000;
--bg-color: #FFFFFF;
}
.text {
color: var(--text-color);
background-color: var(--bg-color);
}
검증 방법
Lighthouse의 Accessibility 탭으로 대비 점수 확인.
색맹 시뮬레이터로 가독성 테스트.
고대비 모드에서 스타일 확인(Windows: Win + Ctrl + C).
시멘틱 HTML: <button>, <nav>로 구조를 명확히 하고 스크린 리더 호환성을 높인다.
ARIA 속성: aria-live, aria-label로 동적 콘텐츠를 보조 기술에 전달.
키보드 접근: tabindex, 포커스 스타일, Tab 트랩으로 모든 기능을 키보드로 조작 가능하게.
색상 대비: 4.5:1 대비 유지, 색상 외 단서 제공, 고대비 모드 지원.