Skip to content

1-2. 시맨틱 HTML ​

한 줄 요약: 문서를 소비하는 기계(검색 엔진, 스크린 리더, 크롤러)의 관점을 이해하고, 상황에 맞는 시맨틱 요소를 근거를 갖고 선택할 수 있다.

학습 목표 ​

  • 시맨틱 마크업의 실제 소비자가 누구인지, 각 소비자가 무엇을 얻는지 설명할 수 있다.
  • 랜드마크 요소(header, nav, main 등)로 페이지 구조를 설계할 수 있다.
  • article / section / div 중 무엇을 쓸지 판단 기준을 갖고 선택할 수 있다.
  • HTML5 아웃라인 알고리즘이 폐기된 배경을 알고, heading 레벨을 직접 관리할 수 있다.

배경: 왜 이것이 존재하는가 ​

<div>와 <article>은 브라우저 화면에서 완전히 똑같이 렌더링된다. 스타일 차이가 없다면 태그 선택이 왜 중요한가 — 이 질문에 답하려면 HTML의 소비자가 사람만이 아니라는 사실에서 출발해야 한다.

API를 설계해 본 개발자라면 이렇게 비유할 수 있다. 모든 응답 필드를 data1, data2로 명명해도 프로그램은 돌아간다. 하지만 그 API를 소비하는 쪽은 각 필드가 무엇인지 알 수 없다. <div>만으로 만든 문서가 정확히 그 상태다. 모든 컬럼이 varchar인 테이블, 필드명이 전부 익명인 스키마다. 시맨틱 요소는 문서라는 데이터에 타입과 이름을 부여하는 일이다.

그 이름을 읽는 소비자는 실재한다:

  • 검색 엔진 크롤러 — 어디가 본문이고 어디가 내비게이션·광고인지 구조로 판별해 색인 품질과 랭킹에 반영한다.
  • 스크린 리더 — 문서에서 파생된 접근성 트리(accessibility tree)를 읽는다. 랜드마크와 heading은 시각장애 사용자의 "스크롤"이자 "목차"다. (1-7에서 상세히 다룬다.)
  • 브라우저 리더 모드 — <article>과 heading 구조를 단서로 본문만 추출한다.
  • 스크래퍼와 LLM — 구조화된 문서일수록 기계 독해의 정확도가 올라간다.

즉 시맨틱은 미적 취향이 아니라, 사람 외의 소비자를 위한 인터페이스 설계다.

핵심 개념 ​

랜드마크: 페이지의 최상위 구조 ​

전형적인 페이지의 골격은 다음과 같다.

html
<body>
  <header>
    <a href="/"><img src="/logo.svg" alt="서비스 로고"></a>
    <nav aria-label="주 메뉴">
      <ul>
        <li><a href="/products">상품</a></li>
        <li><a href="/about">소개</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <!-- 이 페이지의 고유 콘텐츠. 문서당 정확히 1개 -->
  </main>

  <aside>
    <!-- 본문과 간접적으로만 관련된 것: 추천 목록, 광고 -->
  </aside>

  <footer>
    <p>© 2026 Example Corp.</p>
  </footer>
</body>

각 요소의 선택 기준:

요소의미판단 기준
header도입부/머리말로고·제목·주 내비게이션 묶음. 페이지 최상단뿐 아니라 article 내부에도 쓸 수 있다
nav주요 내비게이션 블록링크 묶음이라고 전부 nav가 아니다. "사용자가 이동 수단으로 찾을 만한" 주요 그룹만
main페이지 고유 콘텐츠문서당 1개. 헤더·푸터처럼 페이지 간 반복되는 부분은 제외
aside간접 관련 콘텐츠그 블록을 삭제해도 본문 이해에 지장이 없는가
footer꼬리말저작권, 관련 링크, 작성자 정보

nav가 여러 개라면(주 메뉴 + 페이지 내 목차) aria-label로 구분해 주는 것이 스크린 리더 사용자에 대한 예의다.

이 요소들이 "랜드마크"로 동작하는 것은 관행이 아니라 표준 매핑이다. HTML-AAM(HTML Accessibility API Mappings) 스펙이 각 요소의 암시적 ARIA role을 정의한다: header→banner, nav→navigation, main→main, aside→complementary, footer→contentinfo. 여기에 함정이 하나 있다 — header와 footer는 body 직속일 때만 랜드마크 role을 갖는다. article이나 section 안에 중첩되면 같은 태그가 generic으로 강등된다(그 글의 머리말일 뿐 페이지의 배너가 아니므로). section도 접근 가능한 이름(aria-label 등)이 있을 때만 region 랜드마크가 된다. "시맨틱 요소를 썼는데 스크린 리더 랜드마크 목록에 안 보인다"는 미스터리의 답은 대부분 이 조건부 매핑이다.

article vs section vs div — 판단 플로차트 ​

가장 자주 헷갈리는 3종의 선택 기준은 질문 두 개로 정리된다.

  1. 이 블록을 떼어내 RSS 피드나 다른 페이지에 실어도 독립적으로 성립하는가? → 성립하면 <article>. 블로그 글, 뉴스 기사, 상품 카드, 댓글 하나하나가 해당한다. "기사"라는 이름에 갇힐 필요 없다. 스펙의 정의는 "자기 완결적(self-contained) 구성물"이다.
  2. (독립적이지 않다면) 이 블록은 제목을 붙일 만한 주제 단위인가? → 그렇다면 <section>. 섹션은 원칙적으로 heading을 가져야 한다. 제목을 붙일 수 없다면 그것은 주제 단위가 아니라는 신호다.
  3. 둘 다 아니고 스타일링이나 스크립트 걸이(hook)가 필요할 뿐이라면 → <div>. div를 쓰는 것 자체는 잘못이 아니다. 의미가 없는 곳에 의미 없는 요소를 쓰는 것은 정확한 선택이다.
html
<!-- ❌ 의미 단위와 스타일 단위를 구분하지 않음 -->
<div class="post">
  <div class="post-title">CSS 캐스케이드 이해하기</div>
  <div class="post-body">...</div>
</div>

<!-- ✅ 독립 콘텐츠는 article, 제목은 heading, 순수 래퍼만 div -->
<article class="post">
  <h2>CSS 캐스케이드 이해하기</h2>
  <div class="post-body">...</div>
</article>

heading 계층: 아웃라인은 당신이 직접 관리한다 ​

HTML5 초기 스펙에는 "아웃라인 알고리즘"이 있었다. section이 중첩될 때마다 heading 레벨이 자동 재계산되어, 어디서든 <h1>만 쓰면 된다는 설계였다. 이 알고리즘은 구현한 브라우저·보조기술이 하나도 없었고, 2022년 스펙에서 공식 폐기됐다. 오래된 블로그 글이 여전히 "섹션마다 h1을 쓰라"고 가르치므로 주의가 필요하다.

현실의 규칙은 단순하다:

  • 페이지의 대표 제목으로 <h1> 하나.
  • 이하 h2 → h3 → …로 레벨을 건너뛰지 않고 내려간다. 스크린 리더 사용자는 heading 목록만 뽑아 문서를 탐색하는데, 레벨 점프는 목차의 단절로 들린다.
  • 시각적 크기 때문에 heading 레벨을 고르지 않는다. 구조상 h2인데 작게 보이고 싶다면 CSS로 줄인다. 구조와 표현의 분리가 여기서 실전이 된다.
html
<!-- ❌ 크기를 이유로 레벨 선택 -->
<h1>상품 목록</h1>
<h4>오늘의 특가</h4> <!-- h2를 건너뜀: 구조 단절 -->

<!-- ✅ 구조는 heading으로, 크기는 CSS로 -->
<h1>상품 목록</h1>
<h2 class="text-sm">오늘의 특가</h2>

그 밖의 의미 단위들 ​

전부 외울 필요는 없고, "이 데이터에 더 정확한 타입이 있지 않을까"라고 의심하는 습관이 중요하다. 실무 빈도가 높은 것만 추리면:

  • <button> vs <a> — 1-1에서 정리한 대로 동작이면 버튼, 이동이면 링크.
  • <ul>/<ol>/<dl> — 순서 유무, 이름-값 쌍(정의 목록). 스크린 리더는 "목록, 항목 7개"처럼 개수까지 읽어 준다.
  • <time datetime="2026-07-05"> — 사람용 표기와 기계용 ISO 표기를 분리한다.
  • <figure> + <figcaption> — 본문에서 참조되는 독립 자료(이미지, 코드, 표)와 캡션.
  • <strong>(중요)과 <em>(강세) vs <b>/<i>(순수 표현) — 전자는 의미를 전달하고, 후자는 스타일만 바꾼다.

SEO의 입구: 메타데이터 ​

검색·공유 노출은 본문 마크업 외에 <head>의 메타데이터가 좌우한다. 최소 세트:

html
<head>
  <title>상품명 — 서비스명</title> <!-- 검색 결과의 제목줄 -->
  <meta name="description" content="검색 결과에 표시될 요약. 150자 내외.">

  <!-- Open Graph: 메신저·SNS 공유 카드 -->
  <meta property="og:title" content="상품명">
  <meta property="og:description" content="공유 카드에 표시될 설명">
  <meta property="og:image" content="https://example.com/og.png">

  <link rel="canonical" href="https://example.com/products/1"> <!-- 중복 URL의 대표 지정 -->
</head>

구조화 데이터(JSON-LD)를 넣으면 검색 결과에 별점·가격 같은 리치 결과가 노출될 수 있다는 것까지만 알아 두자. 상세 스키마는 schema.org와 Google 검색 센터 문서가 1차 자료다.

실무 관점 ​

  • div 수프는 리팩터링 비용으로 돌아온다. 시맨틱 없는 코드베이스는 "이 div가 본문인가 사이드바인가"를 사람이 클래스명으로 추적해야 한다. 시맨틱 요소는 코드를 읽는 동료에게도 문서 구조를 전달하는 수단이다.
  • 과잉 시맨틱도 안티패턴이다. 모든 div를 section으로 바꾸는 것은 개선이 아니다. heading 없는 section, 내비게이션 아닌 링크 묶음의 nav는 오히려 접근성 트리에 소음을 만든다. 의미가 없으면 div가 정답이다.
  • CSS 클래스와 시맨틱은 직교한다. class="header"를 붙인 div는 기계에게 아무 의미가 없다. 반대로 <header>에 어떤 클래스를 붙여도 의미는 유지된다. 스타일 시스템(클래스)과 의미 계층(요소)을 별개 축으로 설계한다.
  • 검증 도구: DevTools의 Accessibility 패널에서 랜드마크·heading 구조가 어떻게 노출되는지 확인할 수 있다. Lighthouse의 SEO/Accessibility 감사도 기본 점검으로 유용하다.
  • 프레임워크 시대에도 유효하다. React 컴포넌트(Phase 4)가 최종적으로 뱉는 것도 결국 이 HTML이다. 컴포넌트 내부에서 <div> 대신 무엇을 반환할지의 판단 기준은 지금 이 문서 그대로다.

더 깊이 ​

리더 모드는 확률적으로 동작한다. 브라우저 리더 모드의 계보는 Mozilla의 Readability 라이브러리다. 이 알고리즘은 시맨틱 태그만 믿지 않는다 — 텍스트 밀도(링크 대비 본문 비율), 문단 수, 클래스/ID 이름에 든 힌트(content, article 은 가점, sidebar, comment 는 감점) 등을 종합해 "본문일 확률"을 점수화한다. 즉 <article>을 썼다고 본문 추출이 보장되는 것이 아니라 강한 가점을 받는 것이다. 시맨틱이 잘못된 문서도 추출될 수 있고, 잘된 문서도 광고 div가 본문 한복판에 있으면 오염된다. 시맨틱은 이 확률 게임에서 신뢰도 높은 신호를 공급하는 일이라고 이해하는 것이 정확하다.

구조화 데이터는 마크업과 분리하는 것이 승자가 됐다. 검색 엔진용 구조화 데이터에는 역사적으로 두 방식이 경쟁했다 — 기존 요소에 속성을 얹는 microdata(itemscope/itemprop)와, 본문과 분리된 JSON 블록인 JSON-LD. Google이 권장하는 쪽은 JSON-LD인데, 이유가 설계 교훈으로 남을 만하다: 데이터가 마크업 구조에 결합되면 리팩터링(태그 교체, 컴포넌트 분리)할 때마다 데이터가 함께 깨지고, 검증도 어렵다. 분리된 JSON은 마크업과 독립적으로 생성·검증·교체할 수 있다.

html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "상품명",
  "offers": { "@type": "Offer", "price": "39000", "priceCurrency": "KRW" }
}
</script>

단, JSON-LD는 본문과 분리된 만큼 본문과 어긋날 수 있다 — 가격이 마크업에선 바뀌고 JSON에선 안 바뀌는 류의 불일치는 검색 엔진 패널티 대상이므로, 실무에서는 둘을 같은 데이터 소스에서 렌더링한다.

정리 ​

  • 시맨틱 마크업은 사람 아닌 소비자(검색 엔진, 스크린 리더, 리더 모드, 스크래퍼)를 위한 인터페이스다.
  • 랜드마크 요소로 페이지 골격을 잡는다. main은 문서당 1개, nav는 주요 내비게이션에만. header/footer는 body 직속일 때만 랜드마크가 된다.
  • article(독립 성립) → section(제목 있는 주제 단위) → div(의미 없음, 걸이용) 순서로 판단한다.
  • HTML5 아웃라인 알고리즘은 폐기됐다. heading 레벨(h1~h6)은 건너뛰지 않고 직접 관리하며, 크기는 CSS로 조절한다.
  • 의미가 없는 곳에는 div를 쓰는 것이 맞다. 과잉 시맨틱은 소음이다.

확인 문제 ​

1. 쇼핑몰 목록 페이지에서 상품 카드 하나(이미지 + 상품명 + 가격 + 담기 버튼)를 마크업하려 한다. 카드의 루트 요소로 article, section, div 중 무엇이 적절한가? 근거와 함께 답하라.

정답과 해설

article이 적절하다. 상품 카드는 그 자체로 완결된 단위여서 추천 위젯, 검색 결과, 이메일 등 다른 맥락에 떼어 옮겨도 독립적으로 성립한다 — 이것이 article의 판단 기준이다. section은 "떼어낼 수 없지만 제목이 있는 주제 단위"에, div는 의미 없는 스타일 래퍼에 쓴다. (상품명은 카드의 heading으로 마크업하면 목록 전체가 heading 탐색으로 훑어진다.)

2. 디자인 시안에서 페이지 중간의 소제목이 본문 텍스트보다 작게 표시된다. 동료가 "작으니까 <h5>로 하자"고 제안했다. 무엇이 문제이고 어떻게 해야 하는가?

정답과 해설

heading 레벨은 시각적 크기가 아니라 문서 구조상의 깊이로 정해야 한다. 상위가 h2였다면 이 소제목은 h3이어야 하며, h5를 쓰면 h4를 건너뛴 구조 단절이 생겨 스크린 리더의 heading 탐색과 SEO 파싱에서 문서 구조가 왜곡된다. 구조에 맞는 레벨(h3)을 쓰고 크기는 CSS(font-size)로 줄인다.

3. "우리 사이트는 SPA라서 크롤러가 어차피 JS를 실행해야 하니 시맨틱은 의미 없다"는 주장에 반박하라.

정답과 해설

크롤러가 JS를 실행해 얻는 최종 결과물도 결국 DOM, 즉 HTML 구조다. 렌더링 방식과 무관하게 그 DOM이 div 수프라면 본문/내비게이션 판별, 리치 결과, 접근성 트리 품질이 모두 떨어진다. 또한 시맨틱의 소비자는 검색 엔진만이 아니다 — 스크린 리더와 리더 모드는 런타임 DOM을 실시간으로 소비하므로 SPA에서도 동일하게 시맨틱의 영향을 받는다.

참고 자료 ​