시맨틱 마크업은 왜 접근성과 SEO의 출발점이 되는가
빠른 답
- 시맨틱 마크업은 화면 모양보다 콘텐츠의 역할과 관계를 HTML 구조에 남기는 작성 방식이다.
- 접근성에서는 제목, 랜드마크, 버튼과 링크의 역할이 스크린 리더와 키보드 탐색의 기준이 된다.
- SEO에서는 주요 콘텐츠, 제목 계층, 링크 구조가 검색 엔진이 문서를 이해하는 단서가 된다.
- CSR에서도 최종 DOM의 의미 구조는 중요하지만, 공개 콘텐츠라면 초기 HTML에 무엇이 들어 있는지도 함께 봐야 한다.
목차
점검 매트릭스
시맨틱 마크업은 태그 이름보다 의미 구조에 가깝다
시맨틱 마크업은 특정 요소 이름을 많이 쓰는 기법이 아니다. 페이지 안의 콘텐츠가 어떤 역할을 하는지 브라우저, 보조 기술, 검색 엔진이 해석할 수 있도록 구조를 남기는 방식이다.
같은 박스처럼 보이는 영역도 문서 안에서는 서로 다른 의미를 가진다. 어떤 영역은 사이트 전체 탐색이고, 어떤 영역은 본문이며, 어떤 영역은 독립적으로 읽을 수 있는 글이고, 어떤 영역은 단순한 장식일 수 있다. CSS는 화면 표현을 바꾸지만, 콘텐츠의 역할까지 항상 전달하지는 않는다.
예를 들어 큰 글씨와 굵은 스타일은 사람 눈에는 제목처럼 보일 수 있다. 그러나 문서 구조에서 제목으로 노출되지 않으면 스크린 리더의 제목 목록에도 잡히지 않고, 자동 테스트에서도 제목 역할로 찾기 어렵다. 반대로 올바른 제목 구조와 랜드마크를 가진 문서는 스타일이 일시적으로 깨져도 문서의 뼈대는 유지된다.
실제로 자주 막히는 지점은 컴포넌트 이름과 최종 DOM의 의미가 다르다는 데 있다. 파일명이 Header라고 해서 접근성 트리에서 머리말 역할을 한다고 보장되지는 않는다. 디자인 시스템의 Text 컴포넌트가 화면에서는 제목처럼 보이더라도, 최종 결과가 일반 텍스트라면 문서 구조는 제목을 잃는다.
점검할 때는 다음 질문이 도움이 된다.
- 이 영역은 페이지 전체에서 어떤 역할을 하는가?
- 제목만 훑어도 문서의 큰 흐름이 보이는가?
- 사용자가 키보드만으로 주요 기능에 도달할 수 있는가?
- 링크와 버튼의 차이가 실제 동작과 맞는가?
- 클라이언트 렌더링 이후에도 같은 의미가 유지되는가?
브라우저와 보조 기술은 구조를 기준으로 해석한다
브라우저는 HTML을 파싱해 DOM을 만들고, 스타일과 레이아웃을 계산해 화면에 그린다. 접근성 측면에서는 여기서 한 단계 더 나아가 접근성 트리가 만들어진다. 접근성 트리는 모든 노드를 그대로 복사한 결과가 아니라, 사용자가 이해하고 조작해야 하는 역할, 이름, 상태, 관계를 중심으로 구성된다.
사용자는 스크린 리더의 제목 목록, 랜드마크 목록, 링크 목록을 통해 페이지를 빠르게 훑는다. 문서 구조가 흐리면 사용자는 페이지를 처음부터 끝까지 선형으로 들어야 하고, 원하는 본문이나 기능으로 이동하는 비용이 커진다. 키보드 사용자도 비슷하다. 시각적으로는 버튼처럼 보이지만 포커스가 가지 않는 요소는 실제 조작 흐름에서 빠져 버린다.
검색 엔진이 보조 기술과 동일하게 동작한다고 볼 수는 없지만, 문서 이해에 필요한 단서는 겹친다. 대표 제목, 본문 영역, 내부 링크, 이미지 대체 텍스트, 페이지 간 연결은 검색 엔진이 문서의 주제와 구조를 추론하는 데 도움을 준다. 시맨틱 마크업만으로 검색 순위가 보장되지는 않지만, 문서를 오해하게 만드는 불필요한 손실은 줄일 수 있다.
관련 기준을 더 확인할 때는 MDN의 HTML 요소 레퍼런스, W3C WAI의 접근성 기초 문서, Google 검색의 JavaScript SEO 가이드를 함께 보면 좋다.
점검 순서는 제목, 랜드마크, 상호작용부터 잡는다
시맨틱 마크업을 점검할 때 요소 이름 목록부터 외우면 적용 기준이 흔들리기 쉽다. 먼저 페이지를 읽는 순서와 역할을 본 뒤, 그 역할에 맞는 기본 요소를 선택하는 흐름이 더 안정적이다.
첫 번째는 제목 구조다. 페이지의 대표 제목이 있고, 그 아래 하위 제목들이 논리적인 포함 관계로 이어지는지 확인한다. 제목 수준은 글자 크기를 정하는 도구가 아니라 문서 목차를 만드는 도구에 가깝다. 작게 보이는 제목이 필요하면 제목 수준을 낮추기보다 스타일을 조정하는 편이 구조를 유지하기 쉽다.
두 번째는 랜드마크 구조다. 전역 탐색, 주요 콘텐츠, 보조 영역, 바닥글이 모두 같은 일반 컨테이너로만 되어 있으면 페이지의 큰 지도가 사라진다. 사용자가 반복되는 메뉴를 지나 본문으로 바로 이동할 수 있는지, 자동화 도구가 주요 콘텐츠를 역할 기준으로 찾을 수 있는지 확인해야 한다.
세 번째는 상호작용 요소다. 페이지 이동은 링크, 현재 화면에서 동작을 실행하는 기능은 버튼이라는 기준을 지키면 키보드 조작과 보조 기술 안내가 단순해진다. 일반 컨테이너에 클릭 이벤트만 붙이면 포커스, Enter 또는 Space 동작, 비활성 상태, 접근성 이름을 직접 챙겨야 한다.
품질 기준은 테스트 종류별로 나누면 운영하기 쉽다.
- 단위 테스트: 메뉴 생성 함수나 제목 목록 생성기처럼 순수 로직이 있을 때 구조 규칙을 확인한다.
- 통합 테스트: 렌더링된 페이지에 대표 제목, 탐색, 본문 역할이 존재하는지 확인한다.
- E2E 테스트: 키보드 이동, 주요 링크 이동, 폼 제출처럼 사용자가 실제로 수행하는 흐름을 검증한다.
- 스모크 테스트: 배포된 URL에서 제목, 주요 탐색, 본문 영역이 깨지지 않았는지 빠르게 확인한다.
- 회귀 테스트: 이전에 발생한 접근성 이슈가 다시 생기지 않도록 실패 케이스를 고정한다.
문서 구조를 먼저 모델링해 본다
블로그 상세 페이지를 예로 들면, 화면 구현 단위와 문서 역할 단위가 항상 일치하지 않는다. 상단에는 사이트 이름과 전역 탐색이 있고, 본문에는 글 제목, 작성 정보, 본문 섹션이 있으며, 하단에는 관련 글이나 정책 링크가 있을 수 있다.
처음부터 코드로 들어가기보다 구조를 먼저 적어보면 역할이 더 잘 보인다.
페이지
머리말
사이트 이름
전역 탐색
주요 콘텐츠
글
글 제목
작성 정보
첫 번째 본문 섹션
두 번째 본문 섹션
관련 글
바닥글
저작권 정보
정책 링크
이 구조에서 글은 독립적으로 읽을 수 있는 콘텐츠 단위이고, 본문 섹션은 글 내부의 하위 주제를 나누는 단위다. 전역 탐색은 사이트 전체 이동을 담당하고, 관련 글은 본문 이해를 보조하지만 본문 자체는 아니다.
반대로 모든 영역을 박스로만 바라보면 다음처럼 의미가 흐려진다.
페이지
박스
박스
박스
박스
박스
텍스트
텍스트
박스
박스
사람은 위치와 스타일을 보고 대략 이해할 수 있지만, 키보드 사용자나 스크린 리더 사용자는 구조적 단서를 잃는다. 검색 엔진도 주요 콘텐츠와 반복 영역을 구분하기 어려워질 수 있다. 시맨틱 마크업은 이 차이를 줄이는 기준선이다.
버튼처럼 보이는 것과 버튼으로 동작하는 것은 다르다
시맨틱 마크업의 문제는 레이아웃보다 상호작용에서 더 자주 드러난다. 아래 예시는 버튼처럼 보이지만 실제 의미 정보가 부족한 UI를 단순화한 것이다.
const weakUi = {
node: "generic-container",
text: "저장",
style: "button-like",
onClick: "saveForm"
};
이 구조는 마우스로 클릭할 때는 동작할 수 있다. 그러나 키보드 포커스가 가능한지, Enter나 Space로 실행되는지, 보조 기술이 버튼으로 읽는지, 비활성 상태가 전달되는지는 별도로 확인해야 한다.
의미 중심으로 보면 같은 UI는 다음 조건을 만족해야 한다.
const semanticUi = {
role: "button",
accessibleName: "저장",
action: "submit-current-form",
keyboard: ["Enter", "Space"],
disabledState: false
};
실제 구현에서는 가능한 한 기본 상호작용 요소를 사용하는 편이 좋다. 기본 요소는 역할, 키보드 동작, 상태 전달의 상당 부분을 브라우저가 이미 처리한다. 커스텀 컴포넌트가 필요하더라도 최종 결과가 사용자에게 어떤 역할과 이름으로 노출되는지 확인해야 한다.
자동 테스트도 이 기준에 맞춰 작성할 수 있다. CSS 클래스나 내부 구현 이름보다 사용자가 인식하는 역할과 이름으로 요소를 찾으면 접근성 문제를 더 빨리 발견할 수 있다.
import { test, expect } from "@playwright/test";
test("저장 동작은 사용자에게 버튼으로 노출된다", async ({ page }) => {
await page.goto("/settings");
const saveButton = page.getByRole("button", { name: "저장" });
await expect(saveButton).toBeVisible();
await saveButton.press("Enter");
await expect(page.getByText("설정이 저장되었습니다")).toBeVisible();
});
이 테스트는 버튼이 화면에 있는지만 보지 않는다. 브라우저의 역할 기준으로 찾을 수 있는지, 키보드 입력으로 동작하는지까지 확인한다. 배포 전 품질 게이트로 쓰기에 좋은 형태다.
자동 점검과 CI 품질 게이트를 둔다
시맨틱 마크업은 코드 리뷰만으로 유지하기 어렵다. 페이지가 늘어나고 컴포넌트가 재사용되면 제목 계층, 랜드마크, 버튼 역할, 링크 이름이 쉽게 흔들린다. 그래서 정적 점검과 브라우저 기반 점검을 CI에 함께 넣어 두는 편이 운영 부담을 줄인다.
다음은 접근성 린트와 E2E 테스트를 함께 실행하는 간단한 구성 예시다.
name: quality-gate
on:
pull_request:
push:
branches: [main]
jobs:
semantic-accessibility:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm run lint
- run: npm run test:e2e
- run: npm run test:smoke
프로젝트마다 도구는 달라질 수 있지만, 역할은 나누는 편이 좋다. 린트는 대체 텍스트 누락, 잘못된 역할 사용, 클릭 이벤트만 가진 비상호작용 요소처럼 정적으로 잡을 수 있는 문제에 적합하다. E2E와 스모크 테스트는 실제 브라우저에서 렌더링된 결과를 기준으로 제목, 탐색, 본문, 키보드 흐름을 확인한다.
명령 구성은 다음처럼 단순하게 시작할 수 있다.
{
"scripts": {
"lint": "eslint src",
"test:e2e": "playwright test",
"test:smoke": "playwright test tests/smoke"
}
}
CI가 남겨야 하는 실패 증거도 중요하다. 실패한 URL, 스크린샷, 접근성 리포트, 브라우저 콘솔 로그가 남아야 원인을 좁히기 쉽다. “버튼을 찾지 못했다”보다 “역할이 button이고 이름이 저장인 요소를 찾지 못했다”는 증거가 훨씬 다루기 쉽다.
배포 후 스모크 테스트는 범위를 좁게 잡는 편이 좋다. 대표 제목이 있는지, 주요 탐색과 본문이 역할 기준으로 조회되는지, 핵심 CTA가 키보드로 실행되는지 정도를 빠르게 확인한다. 이 검사는 모든 접근성 문제를 해결해 주지는 않지만, 큰 구조가 깨진 배포를 막는 방어선이 된다.
import { test, expect } from "@playwright/test";
test("문서의 기본 구조가 유지된다", async ({ page }) => {
await page.goto("/articles/semantic-markup");
await expect(page.getByRole("heading", {
name: "시맨틱 마크업은 왜 접근성과 SEO의 출발점이 되는가"
})).toBeVisible();
await expect(page.getByRole("navigation")).toBeVisible();
await expect(page.getByRole("main")).toBeVisible();
});
CSR 환경에서는 초기 HTML과 최종 DOM을 나누어 본다
CSR 환경에서도 시맨틱 마크업은 여전히 중요하다. 사용자가 실제로 조작하는 것은 렌더링 이후의 DOM이고, 스크린 리더와 브라우저 자동화 도구도 이 결과를 기준으로 페이지를 해석하기 때문이다.
다만 SEO 관점에서는 한 가지를 더 나누어 봐야 한다. 검색 엔진이나 소셜 미리보기 수집기, 사내 검색 인덱서, 모니터링 도구가 JavaScript 실행 전의 초기 HTML만 읽을 수 있기 때문이다. Google처럼 JavaScript 렌더링을 처리하는 검색 엔진도 있지만, 모든 크롤러가 같은 수준의 렌더링을 보장하지는 않는다.
따라서 CSR 페이지는 두 질문을 분리해서 점검하는 편이 좋다.
- 최종 DOM: 사용자가 보는 화면에 제목, 본문, 탐색, 버튼과 링크의 의미가 남아 있는가?
- 초기 HTML: 공개 콘텐츠의 제목, 설명, 주요 본문, 링크가 JavaScript 실행 전에도 어느 정도 읽히는가?
- 메타 정보: 검색 결과와 공유 미리보기에 필요한 제목, 설명, 대표 이미지 정보가 서버 응답에 포함되는가?
- 콘텐츠 성격: 로그인 뒤 대시보드인지, 공개 문서인지, 상품 상세인지에 따라 SEO 기준을 다르게 적용하는가?
로그인 뒤에만 보이는 대시보드는 SEO보다 접근성과 키보드 탐색 기준을 우선해도 된다. 반면 공개 문서, 블로그, 상품 상세, 검색 노출이 필요한 목록 페이지는 초기 응답에 핵심 콘텐츠가 비어 있지 않은지 확인해야 한다. 필요하다면 SSR, SSG, 프리렌더링 같은 전략을 함께 검토할 수 있다.
운영 중 자주 깨지는 지점을 미리 본다
시맨틱 구조는 처음 작성할 때보다 변경 과정에서 더 자주 무너진다. 디자인 시스템을 도입하면서 모든 텍스트가 같은 컴포넌트로 감싸지거나, 라우팅을 바꾸면서 대표 제목이 사라지거나, 모달을 추가하면서 포커스 흐름이 끊기는 식이다.
주의할 만한 지점은 다음과 같다.
- 제목 수준을 글자 크기 기준으로 고르는 경우
- 링크와 버튼을 시각적 스타일만으로 구분하는 경우
- 일반 컨테이너에 클릭 이벤트만 붙여 상호작용을 만드는 경우
- ARIA 속성으로 기본 HTML 의미를 과하게 대체하는 경우
- CSR 전환 후 초기 HTML에서 공개 콘텐츠가 비어 버리는 경우
ARIA는 의미를 보충하는 도구이지 기본 요소의 의미를 매번 대체하는 수단은 아니다. 기본 요소로 해결할 수 있는 상호작용을 직접 재구현하면 키보드 이벤트, 상태 전달, 접근성 이름, 포커스 관리를 모두 책임져야 한다. 복잡도가 높아질수록 누락 가능성도 커진다.
운영 기준은 너무 거창할 필요가 없다. 공개 페이지에는 대표 제목과 주요 콘텐츠 영역이 있어야 한다. 전역 탐색은 역할 기준으로 탐색 가능해야 한다. 클릭 가능한 요소는 키보드로도 조작 가능해야 한다. 배포 전에는 정적 검사와 최소 스모크 테스트를 통과해야 한다. 이 정도만 품질 게이트로 두어도 반복되는 실수를 상당히 줄일 수 있다.
시맨틱 마크업은 코드 컨벤션보다 사용자와 문서 사이의 계약에 가깝다. 눈으로 보는 사용자, 키보드로 탐색하는 사용자, 스크린 리더로 듣는 사용자, 문서를 수집하는 검색 엔진은 같은 페이지를 서로 다른 방식으로 읽는다. 그 차이를 견디려면 시각적 배치만이 아니라 의미 구조를 함께 남겨야 한다.
원문 참고
https://www.maeil-mail.kr/question/59
댓글
댓글 쓰기