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

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

GitHub에서 보기 ↗