정보 구조는 화면에 뭘 어디에 놓느냐의 문제이자, 그 자리를 마크업이 얼마나 정직하게 말해 주느냐의 문제입니다. 눈에 보이는 모양이 같아도 div로만 쌓은 화면과 시맨틱 태그로 세운 화면은 검색엔진과 보조기기 앞에서 전혀 다른 대접을 받습니다. div 더미와 시맨틱 마크업을 나란히 놓고 보겠습니다.

20.1 div 더미의 문제

흔히 모든 영역을 div에 클래스만 붙여 구분합니다. 화면상으론 멀쩡하지만 기계는 이 덩어리들이 무슨 역할인지 전혀 알지 못합니다.


<div class="header">
<div class="nav"> ... </div>
</div>
<div class="content">
<div class="post"> ... </div>
</div>
<div class="footer"> ... </div>


클래스 이름은 사람에게만 힌트일 뿐, 브라우저에게 div 는 아무 의미 없는 상자입니다. 화면 낭독기를 쓰는 사람은 여기서 본문이 어디부터인지 건너뛸 방법이 없습니다.

20.2 랜드마크 태그로 세우기

같은 구조를 뜻이 담긴 태그로 바꾸면 각 영역이 자기 역할을 스스로 밝힙니다. 코드 양은 비슷한데 의미가 실립니다.


<header>
<nav> ... </nav>
</header>
<main>
<article> ... </article>
</main>
<footer> ... </footer>


header, nav, main, footer 는 각각 머리말, 길잡이, 본문, 꼬리말이라는 뜻을 담은 랜드마크입니다. 보조기기 사용자는 이 지형지물 사이를 단축키로 곧장 건너뜁니다.

20.3 본문 속 구획 나누기

본문 안에서도 독립적으로 읽히는 덩어리는 article, 주제로 묶인 구획은 section으로 나눕니다. 상자가 아니라 목차가 생기는 셈입니다.


<main>
<section aria-labelledby="new">
<h2 id="new">새 글</h2>
<article> ... </article>
<article> ... </article>
</section>
</main>


sectionaria-labelledby 로 제목을 연결하면 그 구획의 이름이 정해집니다. 각 글은 article 로 감싸 하나씩 떼어 내도 말이 되는 완결된 조각이 됩니다.

20.4 제목 위계 맞추기

제목 태그는 크기 조절용이 아니라 문서의 뼈대입니다. h1부터 순서대로 내려가야 목차가 어긋나지 않습니다.


<h1>커뮤니티</h1>
<h2>자유게시판</h2>
<h3>오늘의 인기글</h3>
<h3>최신글</h3>
<h2>질문답변</h2>


h1은 페이지에 하나, 그 아래로 h2와 h3가 층을 이룹니다. 크게 보이고 싶다고 h3를 h1로 올리면 안 되고, 크기는 CSS로 조절하고 태그는 순서를 지킵니다.

20.5 목록은 목록답게

나열되는 항목을 div로 늘어놓으면 몇 개인지, 어디까지가 한 묶음인지 기계가 못 셉니다. 목록은 ul과 li로 감쌉니다.


<ul class="menu">
<li><a href="/free">자유</a></li>
<li><a href="/qna">질문</a></li>
<li><a href="/news">소식</a></li>
</ul>


낭독기는 이 마크업을 만나면 항목 3개짜리 목록이라고 먼저 알려 줍니다. 사용자는 전체 개수를 듣고 나서 들을지 넘길지 판단할 수 있습니다.

20.6 브레드크럼으로 현재 위치 알리기

깊은 화면에서는 내가 어디쯤 들어와 있는지가 흐려집니다. 이동 경로를 nav로 감싸고 이름을 붙여 위치를 짚어 줍니다.


<nav aria-label="브레드크럼">
<ol>
<li><a href="/">홈</a></li>
<li><a href="/free">자유</a></li>
<li><a aria-current="page">글 제목</a></li>
</ol>
</nav>


순서 있는 목록 ol 이 경로의 위아래를 나타내고, aria-label 이 이 nav가 브레드크럼임을 알립니다. 마지막 항목의 aria-current="page" 는 지금 이 페이지가 여기라고 못박아 줍니다.

20.7 보조 정보는 aside로 물리기

본문 옆에 딸린 추천글이나 광고는 본문과 격이 다릅니다. aside로 감싸 곁다리임을 밝히면 본문에 집중하려는 사람이 통째로 건너뛸 수 있습니다.


<main>
<article> ... </article>
</main>
<aside aria-label="추천 글">
<ul> ... </ul>
</aside>


aside 는 본문과 관련은 있지만 없어도 본문이 성립하는 곁 정보입니다. 이름표를 달아 두면 보조기기가 추천 글 영역이라고 안내하고, 관심 없는 사람은 손쉽게 지나칩니다.

20.8 필요할 때만 role 보태기

시맨틱 태그 대부분은 이미 역할을 갖고 있어 role을 따로 붙일 필요가 없습니다. 다만 태그로 표현 못 하는 역할은 role로 채웁니다.


<div role="search">
<input type="search" aria-label="검색">
</div>

<!-- nav, main 등은 role 불필요 -->
<main> ... </main>


검색 영역처럼 대응하는 태그가 없을 때만 role="search" 를 씁니다. main 에 굳이 role="main" 을 겹쳐 붙이는 것은 군더더기이니, 태그가 이미 말하는 역할은 되풀이하지 않습니다.

20.9 관련 입력을 묶어 주기

폼에서 성격이 같은 입력끼리는 하나의 묶음으로 읽혀야 합니다. fieldset으로 감싸고 legend로 그 묶음의 이름을 답니다.


<fieldset>
<legend>배송 정보</legend>
<label>받는 사람 <input name="name"></label>
<label>주소 <input name="addr"></label>
</fieldset>


legend 가 붙은 fieldset 을 만나면 낭독기는 이 입력들이 배송 정보 묶음이라고 먼저 알립니다. 라디오나 체크박스 그룹에서 특히 힘을 발휘해, 각 선택지가 무엇에 대한 답인지 헷갈리지 않게 해 줍니다.

20.10 정리

정보 구조는 클래스 이름이 아니라 태그의 뜻으로 세워집니다. header와 nav, main, article, section, aside, footer로 지형을 나누고, 제목을 h1부터 층층이 쌓고, 나열은 목록으로 묶고, 경로는 브레드크럼으로 짚어 주면, 눈으로 보든 소리로 듣든 검색엔진이 훑든 같은 뼈대를 읽어 냅니다. 잘 지은 구조는 화면을 바꾸지 않고도 훨씬 많은 사람에게 열려 있습니다.