🏷️
EPISODE 02
랜드마크 · role · aria-* · 키보드 내비게이션 · skip link
시맨틱과 ARIA
시맨틱 태그가 만드는 랜드마크, ARIA의 황금 규칙("No ARIA > Bad ARIA"), role과 aria-label/labelledby/describedby/expanded/hidden, 그리고 tabindex와 skip navigation을 익힙니다.
semanticARIA키보드 내비
소요 시간
⏱ 60분
난이도
📊 중급
선수 조건
🎯 a11y-01
결과물
스크린리더와 키보드만으로 완전히 사용 가능한 컴포넌트
이 강의에서 배우는 것
- 1시맨틱 태그가 만드는 랜드마크와 스크린리더 안내를 안다
- 2ARIA의 황금 규칙을 따른다
- 3role, aria-label/labelledby/describedby를 적재적소에 쓴다
- 4aria-expanded로 토글 상태를 전달한다
- 5tabindex와 skip link로 키보드 내비를 개선한다
1. 시맨틱 → 랜드마크
html
<!-- ✗ -->
<div class="header"><div class="nav">...</div></div>
<!-- ✓ -->
<header><nav>...</nav></header>| 태그 | ARIA 역할 | 스크린리더 안내 |
|---|---|---|
| <header> | banner | 배너 영역 |
| <nav> | navigation | 탐색 영역 |
| <main> | main | 주요 콘텐츠 |
| <aside> | complementary | 보완 영역 |
| <footer> | contentinfo | 콘텐츠 정보 |
| <section> | region | 섹션 |
| <article> | article | 독립적 콘텐츠 |
2. ARIA 황금 규칙
⚠️
“No ARIA is better than Bad ARIA” — 잘못된 ARIA는 없는 것보다 나쁘다. 시맨틱 HTML로 해결할 수 있다면 ARIA를 쓰지 말 것.
3. role
html
<!-- div를 버튼처럼 (피하는 게 좋음) -->
<div role="button" tabindex="0" onclick="..." onkeydown="...">
클릭
</div>
<!-- 탭 UI -->
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel1">탭1</button>
<button role="tab" aria-selected="false" aria-controls="panel2">탭2</button>
</div>
<div role="tabpanel" id="panel1">탭1 내용</div>
<div role="tabpanel" id="panel2" hidden>탭2 내용</div>4. aria-label / labelledby / describedby
html
<!-- 텍스트 없는 버튼 -->
<button aria-label="메뉴 닫기">
<svg aria-hidden="true">...</svg>
</button>
<!-- 다른 요소를 레이블로 -->
<h2 id="section-title">최신 상품</h2>
<ul aria-labelledby="section-title">...</ul>
<!-- 모달 제목 -->
<div role="dialog" aria-labelledby="modal-title" aria-modal="true">
<h2 id="modal-title">주문 확인</h2>
</div>
<!-- 추가 설명 -->
<input type="password" id="pw" aria-describedby="pw-hint">
<p id="pw-hint">8자 이상, 대소문자+숫자+특수문자</p>5. aria-expanded / aria-hidden
html
<button aria-expanded="false" aria-controls="menu" onclick="toggleMenu()">
메뉴 열기
</button>
<ul id="menu" hidden>...</ul>
<script>
function toggleMenu() {
const btn = document.querySelector('button');
const menu = document.getElementById('menu');
const isOpen = btn.getAttribute('aria-expanded') === 'true';
btn.setAttribute('aria-expanded', !isOpen);
menu.hidden = isOpen;
}
</script>
<!-- 장식 아이콘은 스크린리더에서 제외 -->
<button>
<svg aria-hidden="true" focusable="false">...</svg>
저장
</button>6. 키보드 내비게이션
html
<!-- tabindex="0": Tab으로 접근 가능 (자연 순서) -->
<div role="button" tabindex="0">클릭 가능</div>
<!-- tabindex="-1": Tab 불가, JS로 focus() 가능 -->
<div id="modal" tabindex="-1">...</div>
<!-- tabindex="1" 이상: 사용 금지! 자연 순서를 깨뜨림 -->7. Skip Navigation Link
긴 네비게이션을 키보드로 매번 통과하지 않게 하는 "본문 바로가기" 링크.
html
<a href="#main-content" class="skip-link">본문 바로가기</a>
<nav>... (긴 내비게이션) ...</nav>
<main id="main-content">
<h1 tabindex="-1">페이지 제목</h1>
</main>css
.skip-link {
position: absolute;
top: -100%;
left: 0;
padding: 8px 16px;
background: #000;
color: #fff;
z-index: 9999;
text-decoration: none;
}
.skip-link:focus { top: 0; }